Pass credentials to WMI query in PowerShell

Jack van Deur
Jack van Deur used Ask the Experts™
on
Hi,

I have a file with all my servers that I read to pass the servername to a wmi query.
I want to log in locally to every server as an administrator so I have to pass credentials like computername\Administrator and the password.

So I need the code below to ask my credentials just once and then pass it to the wmi command untill EOF


 
Get-content <Path to file> | foreach-object {
Get-WMIObject Win32_LogicalDisk -filter “DriveType=3" -credential  $_\Administrator -computer $_ | 
Select SystemName,DeviceID,VolumeName,@{Name=”Size(GB)”;Expression={‘{0:N1}’ -f($_.size/1gb)}},@{
Name=”Free Space(GB)”;Expression={‘{0:N1}’ -f($_.freespace/1gb)}},@{Name=”Free Space(%)”;Expression={
‘{0:P2}’-f(($_.freespace/1gb) / ($_.size/1gb))}} | Out-file -append "<Path to file>" 
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
something like

$cred = Get-Credential
Get-content <Path to file> | foreach-object {
Get-WMIObject Win32_LogicalDisk -filter “DriveType=3" -credential $cred -computer $_ | 
Select SystemName,DeviceID,VolumeName,@{Name=”Size(GB)”;Expression={‘{0:N1}’ -f($_.size/1gb)}},@{
Name=”Free Space(GB)”;Expression={‘{0:N1}’ -f($_.freespace/1gb)}},@{Name=”Free Space(%)”;Expression={
‘{0:P2}’-f(($_.freespace/1gb) / ($_.size/1gb))}} | Out-file -append "<Path to file>" 
}

Open in new window

Jack van DeurApplication Engineer

Author

Commented:
`@Mister Twelve

Nah that's not it. The problem is that I'm dealing with the fact that I need to pass credentals partly from the textfile i.e <servername> \ <credentials>. The server names are in a variable $_. So a locical thing to do was -Credential $_/$cred but when I do that it show a credential gui with the servername and some text about system function bla bla.

So what I realy need is something that passes $_ and $cred together.

Announcing the Winners!

The results are in for the 15th Annual Expert Awards! Congratulations to the winners, and thank you to everyone who participated in the nominations. We are so grateful for the valuable contributions experts make on a daily basis. Click to read more about this year’s recipients!

Jack van DeurApplication Engineer

Author

Commented:
I solved the problem myself.
However it may need a little finetuning.
Anyone care to help?
Echo 'Enter Username:'
$u = read-host
Echo 'Enter password:'
$p = read-host -assecurestring
$fcred = new-object -typename System.Management.Automation.PSCredential -argumentlist $serv"\"$u, $p
$serv = Get-content e:\scripts\servers.txt|foreach-object {Get-WMIObject Win32_LogicalDisk -filter “DriveType=3" -credential $fcred -computer $_|
Select SystemName,DeviceID,VolumeName,
@{Name=”Size(GB)”;Expression={‘{0:N1}’ -f($_.size/1gb)}},
@{Name=”Free Space(GB)”;Expression={‘{0:N1}’ -f($_.freespace/1gb)}},
@{Name=”Free Space(%)”;Expression={‘{0:P2}’-f(($_.freespace/1gb) / ($_.size/1gb))}}|
Out-file -append "e:\scripts\Drive Space.txt"}

Open in new window

Chris DentPowerShell Developer
Top Expert 2010

Commented:

A few changes :)

The most important functional change is to $fcred, it was in the wrong place if you expected it to use the servername as part of the credential string.

Chris
$u = Read-Host -Prompt "Enter Username"
$p = read-host -assecurestring -Prompt "Enter Password"

# Need to start looping before we build the credential
Get-content e:\scripts\servers.txt | ForEach-Object {

  # Make a server specific credential. "System." is implicit.
  $fcred = New-Object Management.Automation.PSCredential -ArgumentList "$_\$u", $p

  # Get the drive details from the computer and select some fields
  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" -Credential $fcred -Computer $_ |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ($_.FreeSpace / $_.Size) }}

# Changed to Export-Csv. For me, CSV and HTML are the most 
# user-friendly output options
} | Export-Csv "Drive Space.csv" -NoTypeInformation

Open in new window

Chris DentPowerShell Developer
Top Expert 2010

Commented:

I missed a comment out.

For the percentage free space. Dividing by 1Gb on each side is pointless, the two (1Gb) values cancel each other out.

e.g.

FreeSpace      Size           Freespace * 1Gb           Freespace
------------  /   -----    =    --------------------   =     -------------
     1Gb           1Gb             Size * 1Gb                     Size

  Original formula                 Simplified             Cancelling out 1Gb

Chris
Jack van DeurApplication Engineer

Author

Commented:
Thank Chris I try it out as soon as I'm back at the office. I'm in class this week so need to wait a few days.

Kind Regards,

JP
Jack van DeurApplication Engineer

Author

Commented:
Chris,

I tried your solution but somehow it didn't work as written. I had to alter it a bit and after a while it was working (for some reason I don't understand I had to add 'system'). The csv part however is not working as it overwrites the csv file again and again. There's no option to append. Only option here (I'm talking PS v1) is to write multiple files and join them afterwards because the csv option is pretty neat.

Also I found that I can run the script under my own account in the majority of cases but need to login as local admin in some cases. Ideally I need the script to check if it can use the current credentials and if it can't I want it to ask for alternate credentials. The problem is that some of the servers are in a different domain with a one way trust.. Sure I could run the script on two sets of server files but that wouldn't be much of a challenge would it.
Chris DentPowerShell Developer
Top Expert 2010

Commented:
> The csv part however is not working as it overwrites the csv file again and again.

It would only do that if you moved it inside the loop. Export-CSV needs a single stream, as you have found, it has no append option. This is why Export-Csv was placed at the very end. This limitation applies to both PowerShell 1 and 2.

> but need to login as local admin in some cases

I'm a little confused about that. You stipulated that the script needed to generate a credential object to use. That's what this line does:

  $fcred = New-Object Management.Automation.PSCredential -ArgumentList "$_\$u", $p

None of the connections are formed using your own account. We can prompt again if you wish?

Chris
Jack van DeurApplication Engineer

Author

Commented:
Chris,

when I run the script as you wrote it I get the below error:

At E:\beheer\Scripts\drivespace.ps1:12 char:11
+     Select  <<<< SystemName, DeviceID, VolumeName,
Select-Object : The operation '[System.UInt64] / [System.UInt64]' is not define

This doesn't make sense to me.

Kind Regards,

JP
PowerShell Developer
Top Expert 2010
Commented:

Oh goody... I think PowerShell 1 has trouble with UInt64, which is exceptionally unhelpful.

We might cast it to Int64, perhaps...

Chris
$u = Read-Host -Prompt "Enter Username"
$p = read-host -assecurestring -Prompt "Enter Password"

# Need to start looping before we build the credential
Get-content e:\scripts\servers.txt | ForEach-Object {

  # Make a server specific credential. "System." is implicit.
  $fcred = New-Object Management.Automation.PSCredential -ArgumentList "$_\$u", $p

  # Get the drive details from the computer and select some fields
  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" -Credential $fcred -Computer $_ |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ([Int64]$_.FreeSpace / [Int64]$_.Size) }}

# Changed to Export-Csv. For me, CSV and HTML are the most 
# user-friendly output options
} | Export-Csv "Drive Space.csv" -NoTypeInformation

Open in new window

Jack van DeurApplication Engineer

Author

Commented:
Chris,

hads off and a deep bow for you.

It works like a charm.

Is it possible to have the script ask for extra credentials because I have servers in domainx and domainY as well as in a DMZ. I allready tried a contruction where I check for errors (see code). This handles two possible credentials but I don't know how to throw a third one in. Also I need to get a visual as to what server the script is working on. In the meantime I'm gonna give you your points as you earned 'm fair and square.
$u = Read-Host -Prompt "Enter Username"
$p = read-host -assecurestring -Prompt "Enter Password"

# Need to start looping before we build the credential
Get-content e:\beheer\scripts\servers.txt | ForEach-Object {

  # Make a server specific credential. "System." is implicit.
  $fcred = New-Object Management.Automation.PSCredential -ArgumentList "$_\$u", $p

  # Get the drive details from the computer and select some fields
  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" -Computer $_ |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ([Int64]$_.FreeSpace / [Int64]$_.Size) }}

if ($error.count -gt 0) 
{
	  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" -Credential $fcred -Computer $_ |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ([Int64]$_.FreeSpace / [Int64]$_.Size) }}
}

} | Export-Csv "e:\beheer\scripts\Drive Space.csv" -NoTypeInformation

Open in new window

Jack van DeurApplication Engineer

Author

Commented:
Great job.
Chris DentPowerShell Developer
Top Expert 2010

Commented:

Hmm well it's not all that easy to do reliably because of how errors are returned from Get-WmiObject (inconsistently).

As you can see, this snippet is a fair bit more complex than the last.

Chris
Function Get-DiskSpace {
  Param(
    [String]$ComputerName = $Env:ComputerName,
    [Management.Automation.PsCredential]$Credential
  )

  $Params = @{"ComputerName" = $ComputerName}
  If ($Credential -And $ComputerName -ne $Env:ComputerName) { 
    $Params.Add("Credential", $Credential) 
  }

  # Get the drive details from the computer and select some fields
  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" @Params -ErrorAction SilentlyContinue -ErrorVariable TempError |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ([Int64]$_.FreeSpace / [Int64]$_.Size) }}
  If ($TempError.Count -ge 1) {
    Throw $TempError[0].Exception
  }
}

#
# Limits the username / password requests
#

$Limit = 3

#
# Get the default user name and password
# 

$DefaultUserName = Read-Host -Prompt "Enter default username"
$DefaultPassword = Read-Host -AsSecureString -Prompt "Enter default password"

# Need to start looping before we build the credential
# Get-Content e:\beheer\scripts\servers.txt | ForEach-Object {
Get-Content servers.txt | ForEach-Object {

  $ComputerName = $_

  Write-Progress -Activity "Getting disk space" -Status $ComputerName

  # Make sure nothing is cached
  $Disks = $Null

  # Set up a loop to deal with credentials for each server - First attempt uses 
  # these default credentials
  $UserName = $DefaultUserName
  $Password = $DefaultPassword
  # $i is a counter, we try $Limit credential requests then give up on the server, when $i matches that
  $i = 1
  Do {
    # Build credential for this iteration of the loop. First pass uses default credentials
    # subsequent passes use requested credentials
    $Credential = New-Object Management.Automation.PSCredential -ArgumentList "$ComputerName\$UserName", $Password

    Try {
      $Disks = Get-DiskSpace -Computer $_ -Credential $Credential
    } Catch [UnauthorizedAccessException] {
      $UserName = Read-Host -Prompt "Re-enter Username ($ComputerName Attempt: $i)"
      $Password = Read-Host -AsSecureString -Prompt "Enter Password ($ComputerName Attempt: $i)"
    } Catch [Exception] {
      # Exit this block otherwise
      $i = $Limit
      Write-Warning "Skipping $ComputerName"
    }

    $i++

  } Until ($Disks -ne $Null -Or $i -ge $Limit)

  If ($Disks) {
    $Disks
  }

} | Export-Csv "e:\beheer\scripts\Drive Space.csv" -NoTypeInformation

Open in new window

Chris DentPowerShell Developer
Top Expert 2010

Commented:

A revision I should have put in before. We don't need the Throw statement I've added to work around a fuzzy moment I was suffering from :)

Chris
Function Get-DiskSpace {
  Param(
    [String]$ComputerName = $Env:ComputerName,
    [Management.Automation.PsCredential]$Credential
  )

  $Params = @{"ComputerName" = $ComputerName}
  If ($Credential -And $ComputerName -ne $Env:ComputerName) { 
    $Params.Add("Credential", $Credential) 
  }

  # Get the drive details from the computer and select some fields
  Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" @Params -ErrorAction Stop |
    Select SystemName, DeviceID, VolumeName,
      @{Name="Size(GB)";Expression={ '{0:N1}' -f ($_.Size / 1Gb)}},
      @{Name="Free Space(GB)";Expression={ '{0:N1}’ -f ($_.FreeSpace / 1Gb)}},
      @{Name="Free Space(%)";Expression={ '{0:P2}' -f ([Int64]$_.FreeSpace / [Int64]$_.Size) }}
}

#
# Limits the username / password requests
#

$Limit = 3

#
# Get the default user name and password
# 

$DefaultUserName = Read-Host -Prompt "Enter default username"
$DefaultPassword = Read-Host -AsSecureString -Prompt "Enter default password"

# Need to start looping before we build the credential
# Get-Content e:\beheer\scripts\servers.txt | ForEach-Object {
Get-Content servers.txt | ForEach-Object {

  $ComputerName = $_

  Write-Progress -Activity "Getting disk space" -Status $ComputerName

  # Make sure nothing is cached
  $Disks = $Null

  # Set up a loop to deal with credentials for each server - First attempt uses 
  # these default credentials
  $UserName = $DefaultUserName
  $Password = $DefaultPassword
  # $i is a counter, we try $Limit credential requests then give up on the server, when $i matches that
  $i = 1
  Do {
    # Build credential for this iteration of the loop. First pass uses default credentials
    # subsequent passes use requested credentials
    $Credential = New-Object Management.Automation.PSCredential -ArgumentList "$ComputerName\$UserName", $Password

    Try {
      $Disks = Get-DiskSpace -Computer $_ -Credential $Credential
    } Catch [UnauthorizedAccessException] {
      $UserName = Read-Host -Prompt "Re-enter Username ($ComputerName Attempt: $i)"
      $Password = Read-Host -AsSecureString -Prompt "Enter Password ($ComputerName Attempt: $i)"
    } Catch [Exception] {
      # Exit this block otherwise
      $i = $Limit
      Write-Warning "Skipping $ComputerName ($($_.Exception))"
    }

    $i++

  } Until ($Disks -ne $Null -Or $i -ge $Limit)

  If ($Disks) {
    $Disks
  }

} | Export-Csv "e:\beheer\scripts\Drive Space.csv" -NoTypeInformation

Open in new window

Jack van DeurApplication Engineer

Author

Commented:
Hey Chris,

this is great. Everything is working like a charm.  Had to upgrade to PSv2.0 for the DO..Try..Catch loop to work but that was a minor issue. You really are a GENIUS for delivering this so fast. I'm a novice (I guess you allready figured that one out) in powershell so it's great to have guys like you help us along.

Gonna try and find out how this works with all the pipes and the curled brackets, where a function starts and stops and where a loop starts and stops. I can read and understand everything you try to do in the script but have some troubles in understanding the flow and the jumps.

Thanks again for the help.

JP

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial