Help with PowerShell v2.

I am trying to collect some computer and monitor information from systems that have PowerShell v2.
If I run the code below when logged in as local admin it runs fine however when I call it from a bat with RunAS it fails.
I’m using "." as the drive letter changes due to running from USB.

I can’t run this remotely either as PowerShell is disabled for remoting. :frowning:

Can anyone tell me what is wrong?

I should have said that I am running this on Windows 7/10 machines.

Bat

powershell.exe "Start-Process powershell.exe -ArgumentList '-ExecutionPolicy Bypass -File .\Monitor-Info.ps1' -Verb RunAs"

PS

$Monitor = Get-WmiObject wmiMonitorID -namespace root\wmi
$Computer = Get-WmiObject -Class Win32_ComputerSystem
$outPath = '.\Audit.csv'

$Monitor | %{
    $psObject = New-Object PSObject
	
	$psObject | Add-Member NoteProperty ComputerName ""
    $psObject | Add-Member NoteProperty ComputerType ""
    $psObject | Add-Member NoteProperty ComputerSerial ""
	
    $psObject | Add-Member NoteProperty MonitorSerial ""
    $psObject | Add-Member NoteProperty MonitorType ""

	$psObject.ComputerName = $env:computername
    $psObject.ComputerType = $Computer.model
    $psObject.ComputerSerial =  $Computer.Name

    $psObject.MonitorSerial = ($_.SerialNumberID -ne 0 | %{[char]$_}) -join ""
    $psObject.MonitorType = ($_.UserFriendlyName -ne 0 | %{[char]$_}) -join ""

        If ($psObject.MonitorSerial -ne 1){
        $psObject | ConvertTo-Csv -NoTypeInformation | Out-File -Append $outPath
        }
} 

Well, First, by default, Win8 is v3, and Win10 is v4 or v5. So, no way are you stuck at v2. You can still use v2 coding to talk to Win8 / 10 though. So, either you must write the script to first determine which PoSH version is installed and run that version specific code branch (if you plan to have that), or use the LCD (lowest common denominator) of v2 version for all.

That being said, without PoSH Remoting enabled, you are might not be to be able to do what you are after from your workstation.
With that, of course, you either need to be an admin in the domain (admin on the remote systems) or explicitly added as an administrator to all the remote systems, or know an account which is and admin to be able to use PoSH Remoting

So, since you need to do this on all systems (RunAs notwithstanding). How do you plan on doing that without PoSH Remoting enabled?

Off the top of my head, this means setting a Task Schedule via GPO which copies your script to each machine to be executed or point to the script on a central share that Everyone has access to and running that script via the Task Schedule with the needed permission / privilege, then saving those results to a local file, that you copy to a central share that you later collect, then combine into whatever report you are after.

FYI…
There are several commands that work on remote systems without the need for Remoting / WinRM.
See: ‘technet.microsoft.com/en-us/library/ff699046.aspx?f=255&MSPPError=-2147217396’

But if you can’t get all you need, using only those item from the article, then you need to either enable PoSH Remoting or use the GPO + scheduled Task approach, or the like.

Also, I’d change your cmd to this…
Start-Process powershell.exe -Credential “DomainNameOrMachineName\UserAccount” -ArgumentList “Start-Process powershell.exe -ExecutionPolicy Bypass -File ‘.\Monitor-Info.ps1’ -Verb RunAs”

Lastly, if that file is not on the remote systems, then you are trying to run this local script on remote hosts, now you have another issue, because it requires remoting to be enabled, because need to use - Invoke-Command

See:
Run a local PowerShell Function against a Remote Computer with PowerShell Remoting
Run a local PowerShell Function against a Remote Computer with PowerShell Remoting · Mike F. Robbins

Similar approaches are possible with the PoSH Using statement, but that is a PoSH v5 thing.

Or download and use SysInternals PSEXEC…
Something like
psexec \server1 cmd /c "echo . | powershell -file "

Sorry, I definitely could have been a bit clearer. 95%+ of these will be Windows 7 (PS2) with the odd few Windows 10, and I was planning to just run this from a USB stick on each machine.
I am a domain admin but I don’t know the Hostname or the IP address of any of these machines (so I can’t use psexec either). I could go around and gather all the hostnames but by the time of done that I might as well just have run the script locally.
The reason I am wanting to use RunAS is that I want to do this during business hours, this means for me to cause minimal interruptions I need to run it while the current user is logged in with admin rights (Domain or Local).

This is hopefully just a stop-gap measure while I convince work to get a proper asset tracking program and update PS and allow remoting. This, unfortunately, will take a month or so to get approved.

I will try the -Credential flag, but I thought I already tried that and it didn’t work, however, that could have been related to another issue now I think back.

Any other ideas let me know, and I’ll try the above tips tomorrow morning.

btw, totally cool that Get-WmiObject works remotely without Remoting / WinRM :slight_smile:

Don’t use % in scripts - it makes them harder to read and update.

I think you should be able to simplify your code to this

$Computer = Get-WmiObject -Class Win32_ComputerSystem
$outPath = '.\Audit.csv'

Get-WmiObject wmiMonitorID -namespace root\wmi | 
foreach {
    
    $props = @{
      ComputerName   = $env:computername
      ComputerType   = $Computer.model
      ComputerSerial =  $Computer.Name
      MonitorSerial = ($_.SerialNumberID -ne 0 | foreach {[char]$_}) -join ""
      MonitorType = ""
    }

    if ($_.UserFriendlyName) {
      $props.MonitorType = ($_.UserFriendlyName -ne 0 | foreach{[char]$_}) -join ""

    }
    
    $psObject = New-Object PSObject -Property $props
	
    $psobject
 ##       If ($psObject.MonitorSerial -ne 1){
 ##       $psObject | ConvertTo-Csv -NoTypeInformation | Out-File -Append $outPath
 ##       }
} 

using Add-member in the way you do was only necessary in PowerShell v1 if I remember correctly.

If you do have to use Add-Member you can create the member and set the value in one go

$psObject | Add-Member NoteProperty ComputerName $env:computername
In a script you should use the parameter names rather than relying on positional parameters

Also notice the change to MonitorType - the userFriendlyName property is often empty which will crash your script if you don’t allow for it

CovertTo-Csv isn’t available in powershell v2

Ditto on what Richard says.

Yet, I noticed other items that jumped out at me in your response to my feedback.

Your comment…
‘I am a domain admin but I don’t know the Hostname or the IP address of any of these machines’

So, these are workgroup machines, not domain joined machines?
If not, setting up PoSH Remoting, requires more work that just running…
Enable-PSRemoting -Force

… via whatever method, you have to do this as well…
blogs.msdn.microsoft.com/wmi/2009/07/24/powershell-remoting-between-two-workgroup-machines

As for this…
‘The reason I am wanting to use RunAs is that I want to do this during business
hours, this means for me to cause minimal interruptions I need to run it while
the current user is logged in with admin rights (Domain or Local).’

So, the local machine user is logged on with local admin rights???
Either way, Windows security boundaries / protections, will prevent you from doing this.

It’s incredibly difficult to impersonate a user without knowing their password (again, imagine the security implications! and of course not something you can dynamically do / get). To do this, you’d have to change every users password, have that user logon with the new creds, do your thing, then have them change their password again so that only they know what it is, then log off an back on with the new creds. Talk about disruptive.

It’s better to run it as either a logon or logoff script or one once Scheduled Task or you are back to PSEXEC.
If these are domain joined machines and you need to get them all, the you can get all hostnames and IPA’s directly from AD/DNS of course, this way…

(Get-ADComputer -Filter *).Name | Resolve-DnsName

… I am sure you knew that already though.

Richard, thanks for the tip on Add-Member. never noticed that had changed and just always did it that way before.

postanote, just wow… you really just ran away with all this…

So, these are workgroup machines, not domain joined machines?
No, they are Domain joined but I am trying to audit just one level of our building, therefore I can't just use PowerShell remoting against whole OU as it contains all computers in the building, for this reason, lots of options go out the window. Also, can't use group policy as I have no way to target these machines directly etc.
So, the local machine user is logged on with local admin rights??? Either way, Windows security boundaries / protections, will prevent you from doing this.
No. Of cause not. I wish to run the script from a USB drive as either a Domain Admin or Local Admin (not under the computers current users domain account as they obviously don't have permissions).
It's better to run it as either a logon or logoff script or one once Scheduled Task or you are back to PSEXEC. If these are domain joined machines and you need to get them all, the you can get all hostnames and IPA's directly from AD/DNS of course, this way...
The point of this script was to run it from each computer's desktop. Not use remoting as we are not set up for it at this time. For now, I am just going to manually gather this info (by hand), something with RunAs command just stops me from being able to run the script and I couldn't work out what it was. For the future, I will resolve this with proper tools.