0

I'm editing the original question, since it's getting marked as duplicate for the original question and adding single quotes instead of double still has this blank StarTime issue.

I'm trying to run this powershell as a shell command, and for some reason, it has an error in a Windows shell, but in a script it doesn't:

This is my shell command:

powershell "$today=[system.datetime](Get-Date); $startTime=$today.AddHours(-950); $events = Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Application Error';Data='application.exe';StartTime=$($startTime);EndTime=$($today);} -ErrorAction SilentlyContinue;  foreach ($event in $events) {   $crashOccurredTime=$event.TimeCreated;    $lookForInitStart = $event.TimeCreated.AddMinutes(-2);       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='AppMgr';StartTime=$lookForInitStart;EndTime=$crashOccurredTime;} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};   if($eventInit -ne $null)   {           Write-Host 'Found application.exe after Init TimeCreated $($event.TimeCreated) ProviderName $($event.ProviderName) Message $($event.Message)';   }}"

The error is:

At line:1 char:185
+ ... ication Error';Data='Hop2USB69xxPhotoPrinteru.exe';StartTime=;EndTime ...
+                                                                  ~
Missing statement after '=' in hash literal.
At line:1 char:194
+ ... rror';Data='application.exe';StartTime=;EndTime=;} -Erro ...
+
...

It looks like the time variables are blank when it tires to use them for the FilterHashtable.

Note that this has to be run as a single shell command, not multiple PS commands. I can't save it as a .ps1 script because it gets deployed to 1000's of devices and we'd rather run it separately on the devices to find this sequence. We get the command output back.

If you want to try duplicating it, you might use google as your application name, since you see google on your computer usually, and maybe don't look for the errors, so you get output.

Update: I tried escaped double quotes and still see the same issue:

powershell "$today=[system.datetime](Get-Date); $startTime=$today.AddHours(-950); $events = Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Application Error';Data='application.exe';StartTime=$($startTime);EndTime=$($today);} -ErrorAction SilentlyContinue;  foreach ($event in $events) {   $crashOccurredTime=$event.TimeCreated;    $lookForInitStart = $event.TimeCreated.AddMinutes(-2);       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='AppMgr';StartTime=$lookForInitStart;EndTime=$crashOccurredTime;} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};   if($eventInit -ne $null)   {           Write-Host \"Found application.exe after Init TimeCreated $($event.TimeCreated) ProviderName $($event.ProviderName) Message $($event.Message)\";   }}"

Error:

At line:1 char:185
+ ... ication Error';Data='application.exe';StartTime=;EndTime ...
+                                                                  ~
Missing statement after '=' in hash literal.
At line:1 char:194
+ ... rror';Data='application.exe';StartTime=;EndTime=;} -Erro ...
+                                                                  ~
Missing statement after '=' in hash literal.
At line:1 char:238
+ ... artTime=;EndTime=;} -ErrorAction SilentlyContinue;  foreach ( in ) {  ...
+                                                                  ~
Missing variable name after foreach.
At line:1 char:242
+ ... me=;EndTime=;} -ErrorAction SilentlyContinue;  foreach ( in ) {   =.T ...
+                                                                 ~
Unexpected token ')' in expression or statement.
At line:1 char:397

It looks like the variables are empty and causing the issue. Not sure why.

Update2: I'm testing at the command prompt after typing powershell and return, and then

PS E:\> powershell.exe { $today=[system.datetime](Get-Date); $startTime=$today.AddHours(-950); $events = Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Application Error';Data='application.exe';StartTime=$($startTime);EndTime=$($today);} -ErrorAction SilentlyContinue;  foreach ($event in $events) {   $crashOccurredTime=$event.TimeCreated;    $lookForInitStart = $event.TimeCreated.AddMinutes(-2);       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='AppMgr';StartTime=$lookForInitStart;EndTime=$crashOccurredTime;} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};   if($eventInit -ne $null)   {           Write-Host \"Found application.exe after Init TimeCreated $($event.TimeCreated) ProviderName $($event.ProviderName) Message $($event.Message)\";   }} }

and it seems to be working. I'm not sure if that means my shell command should be this when I run it from our application that runs it:

powershell "powershell.exe { $today=[system.datetime](Get-Date); $startTime=$today.AddHours(-950); $events = Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Application Error';Data='application.exe';StartTime=$($startTime);EndTime=$($today);} -ErrorAction SilentlyContinue;  foreach ($event in $events) {   $crashOccurredTime=$event.TimeCreated;    $lookForInitStart = $event.TimeCreated.AddMinutes(-2);       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='AppMgr';StartTime=$lookForInitStart;EndTime=$crashOccurredTime;} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};   if($eventInit -ne $null)   {           Write-Host \"Found application.exe after Init TimeCreated $($event.TimeCreated) ProviderName $($event.ProviderName) Message $($event.Message)\";   }} }"

When I tried running it from outside the powershell prompt there was an error:

powershell.exe { $today=[system.datetime](Get-Date); $startTime=$today.AddHours(-950); $events = Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='Application Error';Data='application.exe';StartTime=$($startTime);EndTime=$($today);} -ErrorAction SilentlyContinue;  foreach ($event in $events) {   $crashOccurredTime=$event.TimeCreated;    $lookForInitStart = $event.TimeCreated.AddMinutes(-2);       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application';ProviderName='AppMgr';StartTime=$lookForInitStart;EndTime=$crashOccurredTime;} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};   if($eventInit -ne $null)   {           Write-Host \"Found application.exe after Init TimeCreated $($event.TimeCreated) ProviderName $($event.ProviderName) Message $($event.Message)\";   }} }

Error:

'Where-Object' is not recognized as an internal or external command,
operable program or batch file.
Michele
  • 3,617
  • 12
  • 47
  • 81
  • I wouldn't go down that rabit hole for such a long command string. Instead I would use a `base64` string with the [-EncodedCommand](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_powershell_exe#-encodedcommand-base64encodedcommand) parameter. – iRon Aug 02 '22 at 18:40
  • @iRon - what would you suggest it be using base64 and -EncodedCommand – Michele Aug 02 '22 at 18:55
  • 1
    `"` characters embedded in an overall `"..."` string must be _escaped_. Since you're calling the PowerShell CLI, they must be escaped as ``\"`` – mklement0 Aug 02 '22 at 20:30
  • @mklement0 - I'm trying single inner quotes now, and the error has changed to show blank StartTime variable. I'm not sure why that value isn't making it to the command. I re-wrote the question since the single inner quotes didn't completely fix it. – Michele Aug 03 '22 at 16:43
  • The linked answer also explains why embedded `'...'` are _not_ an option if you actually need _string interpolation_ as part of your PowerShell command, which you do; therefore, use embedded `\"...\"`, as also recommended in the previous comment. (I'm assuming you're call from _outside_ PowerShell; from _inside_ PowerShell, it would hypothetically have to be ``\`"...\`"`` (sic), but it's easier and generally better to use a script block `{ ... }` in that case.) – mklement0 Aug 03 '22 at 16:45
  • @mklement0 - I tried the \" inner quotes and it's still showing the time variable as blank in the error. Maybe a scope issue. Not sure – Michele Aug 03 '22 at 16:48
  • This would imply that _up-front_ expansion of variables in your `"..."` string happens, which in turn implies that you're calling _from PowerShell_. In that case, use `powershell.exe { ... }`, as suggested. – mklement0 Aug 03 '22 at 16:56
  • It that still doesn't help, I suggest reverting this question to its original form and asking a _new_ question, in which you clarify what environment your `powershell.exe` call is made from, along with a _minimal_ example that reproduces the problem. – mklement0 Aug 03 '22 at 17:37

1 Answers1

0

I wouldn't go down that rabbit hole for such a long command string. Instead I would use a base64 string with the -EncodedCommand parameter.

To encode your script to Base64:

$Command = {
    $today = [system.datetime](Get-Date); 
    $startTime = $today.AddHours(-900); 
    $events = Get-WinEvent -FilterHashtable @{LogName='Application'; 
    ProviderName='Application Error'; 
    Data='application.exe'; 
    StartTime=$startTime; 
    EndTime=$today} -ErrorAction SilentlyContinue;  
    foreach ($event in $events) 
    {
       $crashOccurredTime = $event.TimeCreated; 
       $lookForInitStart = $event.TimeCreated.AddMinutes(-2);    
       $eventInit = {Get-WinEvent -FilterHashtable @{LogName='Application'; 
       ProviderName='AppMgr';
       StartTime=$lookForInitStart;
       EndTime=$crashOccurredTime} -ErrorAction SilentlyContinue | Where-Object -PipelineVariable Message -Match 'InitApp'};
       if($eventInit -ne $null)
       {
               Write-Host "--------Found application.exe after Init: TimeCreated-$($event.TimeCreated); ProviderName-$($event.ProviderName); --Message-$($event.Message)--------"
       }
    }
}.ToString()
$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Command)
$EncodedCommand = [Convert]::ToBase64String($Bytes)

To launch your (encoded) script:

PowerShell -EncodedCommand $EncodedCommand
iRon
  • 20,463
  • 10
  • 53
  • 79
  • Wouldn't the $command and $bytes, and $EncodedCommand be part of a .ps1 script? I'm not clear on what you're proposing. How would $EncodedCommand get to my shell powershell command? I'm trying to avoid .ps1 files – Michele Aug 02 '22 at 19:57
  • I don't think this is a solution for me. I can't run multiple PS commands at the command line. Has to be a single one. I can't save as a .ps1 file since we are doing this on 1000's of devices. – Michele Aug 03 '22 at 14:33
  • In that case, start digging... Start with escaping (inner) double quotes (`"`) with two double quotes: `""` as @mklement0 points out, also carefully read the duplicates. – iRon Aug 03 '22 at 15:03