I'm trying to run the cmdlet "Get-Printer" and apply it to multiple computers but I get an error message I tried using double quotations marks and get a same error message.
"Get-Printer : Cannot process argument transformation on parameter 'ComputerName'. Cannot convert value to type System.String."
Get-Printer -ComputerName 'server01', 'server02'|select-object -Property Name, PortName |Select-String -Pattern 127.0.0.1
is it because get-printer cmdlet can only be applied to one server at a time? do I have to take a different approach to be able to apply it to multiple servers?
ComputerName is a string not an array. See the documentation for Get-Printer.
You can however use another pipe (|) at the beginning followed by a block beginning with a % (shorthand for ForEach-Object) in order to feed the strings to the cmdlet one at a time. It would look something like this:
'server01', 'server02' |
%{Get-Printer -ComputerName $_} |
Select-Object -Property Name, PortName |
Select-String -Pattern 127.0.0.1
There is a second issue with this though. Select-String also expects a string, but you're passing it an object containing Name and PortName. Instead of using Select-String, you could probably just pipe it to a block prefixed by ? (shorthand for Where-Object) and check if PortName contains 127.0.0.1.
Adding this would look like:
'server01', 'server02' |
%{Get-Printer -ComputerName $_} |
Select-Object -Property Name, PortName |
?{$_.PortName.Contains("127.0.0.1")}
If you would like, you can also shorten Select-Object to just Select, but I'll leave that up to you.
The help of Get-Printer shows that the parameter -ComputerName accepts input of type string, but not string array. So you can only specify a single computer name.
https://learn.microsoft.com/en-us/powershell/module/printmanagement/get-printer?view=windowsserver2019-ps
What you can do however, is to define the array of computer names first and then use a foreach.
$computers = "server01","server02"
foreach($computer in $computers)
{
Get-Printer -ComputerName $computer |select-object -Property Name, PortName | Select-String -Pattern 127.0.0.1
}
Or like Jesse suggested above a one liner would look like this:
"server01","server02" | ForEach-Object {Get-Printer -ComputerName $_} | Select-Object -Property Name, PortName | Select-String -Pattern 127.0.0.1
Related
I am storing the following query value in a variable:
$unquotedPaths = Get-WmiObject -Class Win32_Service | Select-Object -Property Name,DisplayName,PathName,StartMode | Select-String "auto"
The problem starts when i print that variable becouse the variable takes from the query an object which is formed by hashtables like in this output:
PS C:\Users\pc> Get-WmiObject -Class Win32_Service | Select-Object -Property Name,DisplayName,PathName,StartMode | Select-String "auto"
#{Name=AGMService; DisplayName=Adobe Genuine Monitor Service; PathName="C:\Program Files (x86)\Common Files\Adobe\AdobeGCClient\AGMService.exe"; StartMode=Auto}
#{Name=AGSService; DisplayName=Adobe Genuine Software Integrity Service; PathName="C:\Program Files (x86)\Common Files\Adobe\AdobeGCClient\AGSService.exe"; StartMode=Auto}
#{Name=asComSvc; DisplayName=ASUS Com Service; PathName=C:\Program Files (x86)\ASUS\AXSP\1.01.02\atkexComSvc.exe; StartMode=Auto}
#{Name=AudioEndpointBuilder; DisplayName=Compilador de extremo de audio de Windows; PathName=C:\WINDOWS\System32\svchost.exe -k LocalSystemNetworkRestricted -p; StartMode=Auto}
How i can get and output like this:
Name DisplayName PathName Startmode
---------- ------------- ------------ ------------
ExampleName ExampleDisplayName C:\Example Auto
Select-String is meant to search and match patterns among strings and files, If you need to filter an object you can use Where-Object:
$unquotedPaths = Get-WmiObject -Class Win32_Service |
Where-Object StartMode -EQ Auto |
Select-Object -Property Name,DisplayName,PathName,StartMode
If the filtering required more complex logic you would need to change from Comparison Statement to Script Block, for example:
$unquotedPaths = Get-WmiObject -Class Win32_Service | Where-Object {
$_.StartMode -eq 'Auto' -and $_.State -eq 'Running'
} | Select-Object -Property Name,DisplayName,PathName,StartMode
I am attempting to use the -ExpandProperty feature in PowerShell to stop the header appearing in the output and format the date without minutes and seconds. This is just to get the created date for an AD Object:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object -ExpandProperty #{Name="Created";Expression={$_.Created.ToString("yyyy-MM-dd")}}
This does not produce a result, only if I exclude the "-ExpandProperty" part will it produce the right date format BUT includes the header "Created" which I don't want.
Any ideas please?
I don't have access to an AD at the moment, but this could be what you are after
Updated
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created | Select-Object Created | ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}
To complement LotPings' helpful answer, which offers effective solutions:
As for why your code didn't work:
While Select-Object's -Property parameter accepts hashtables that define calculated properties (such as in your code), the -ExpandProperty parameter only accepts a property name, as a string.
Therefore, your hashtable is simply stringified, resulting in string literal System.Collections.Hashtable, causing Select-Object to complain, given that there is no property by that name.
The purpose of -ExpandProperty is to output just a property value rather than a custom object with that property.
You therefore do not need a detour via Select-Object, and can just use the value-outputting script block - { $_.Created.ToString("yyyy-MM-dd") } - directly with ForEach-Object instead, as shown at the bottom of LotPings' answer.
However, there is an obscure feature that you forgo by using ForEach-Object: Select-Object allows combining -ExpandProperty with -Property, in which case the properties specified via -Property are added as NoteProperty members to the value of the property specified via -ExpandProperty:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } |
Select-Object -ExpandProperty one -Property two; $val; $val.two
uno
2
Note how the output string value, 'uno' has a copy of the input object's .two property attached to it.
To emulate that with ForEach requires more work:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } | ForEach-Object {
$_.one + '!' | Add-Member -PassThru two $_.two
}; $val; $val.two
uno!
2
In PowerShell there nearly always is more than one solution to a problem-
(Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} ).Created
or
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} |
Select-Object -Expand Created
Parameter names can be shorted as long as they are uniquely identifiable and there are also shortcuts (uppercase letters) so -EA is -ErrorAction
A calculated property does IMO make no sense here as it is the only output, so this should do also:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}
I'm trying to extract the key for a user but I get unwanted spaces and newlines before the string and after it. My script is the following:
$File = gwmi Win32_UserProfile -co MADS000001 |
select localpath, sid |
Where-Object {$_.localpath -eq "C:\Users\Administrator"} |
select Sid |
ft -HideTableHeaders |
Out-String -Stream
Write-Host $file
How can I get rid of them?
The output looks like this:
I'm not sure of your goal.
If you want to find out the name of the local Administrator account (even if it's been renamed), you can write this:
Get-WmiObject Win32_UserAccount -Filter 'LocalAccount=TRUE AND SID LIKE "%-500"' |
Select-Object -ExpandProperty Name
If you want that user's profile path, you can combine them:
$adminSID = Get-WmiObject Win32_UserAccount -Filter 'LocalAccount=TRUE AND SID LIKE "%-500"' |
Select-Object -ExpandProperty SID
$profilePath = [WMI] "root\cimv2:Win32_UserProfile.SID='$adminSID'" |
Select-Object -ExpandProperty LocalPath
Note the use of Select-Object -ExpandProperty to select a specific property and output only that property.
I think you are over complicating it a bit.
If you just do
$profileInfo = Get-WmiObject Win32_UserProfile -ComputerName 'MADS000001' |
Where-Object {$_.localpath -like "*\Administrator"} |
Select-Object LocalPath, Sid, PSComputerName
You will get an object (if found of course, $null otherwise) with the three properties in the Select-Object command.
The $profileInfo.LocalPath you can use to delete the folder.
The $profileInfo.Sid string value you can use to remove the registry key for that user at
HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<SID>
P.s. The second 'unwanted' whitespace you have outlined is simply a newline Write-Host always adds unless you use Write-Host $profileInfo.Sid -NoNewline
To get the SID for a user:
$userName = "Administrator"
$sid = Get-WmiObject Win32_UserAccount -Filter "LocalAccount=TRUE AND Name='$username'" |
Select-Object -ExpandProperty SID
Note that this will fail if the user is not named Administrator.
Also - note the use of Select-Object -ExpandProperty to select the value of a specific property of an object.
I'm sure this should be straight forward but I've been stuck on it for a while now...
I am trying to get the service names (for sql server) into an array but can't figure out how to do it. I basically want the array contents to look something like the output of this:
Get-Service -computername $server_name -name sql* | format-table -property name
I have tried things like this but the contents of $service_name are very odd:
$service_name = (Get-Service -computername $server_name -name sql* -exclude *sqlwriter | format-table -property name)
Whatever I try either errors or gives some strange message in my array. Should this be easy/possible? I'm guessing I could dump the results in a text file then use the contents of that but it's a bit messy and more overhead than seems necessary.
Not sure, but where you looking for this (with whatever variation on the pattern for -Name and/or -Exclude)?
PS> $names = (Get-Service -Name Sql* | select name)
PS> $names.GetType().IsArray
True
PS> $names.Length
3
PS> $names
Name
----
SQLBrowser
SQLSERVERAGENT
SQLWriter
Or even along the lines of the following if you really want the "Name" as a System.String array.
PS> $names = (Get-Service -Name Sql* | foreach { $_.Name -as [string]})
PS> $names[0].GetType().FullName
System.String
PS> $names
SQLBrowser
SQLSERVERAGENT
SQLWriter
But also keep the good advice in #alroc's answer in mind - maybe you want to keep the actual type of Get-Service's result (System.ServiceProcess.ServiceController) as long as possible and access/use the Name property of it as late as possible. YMMV.
You're using format-table in the pipeline. Anytime you use a format-* cmdlet, that's the end of the line for your data - it's now just a formatted bunch of text, it's no longer data that you can actually use.
Try this to get the names formatted as a table for viewing:
$service_name = (Get-Service -computername $server_name -name sql* -exclude *sqlwriter);
$service_name | format-table -property name;
That said, I ran both your version and mine above and got the same visual output - the critical difference is that mine stores data in $service_name, not just a bunch of text (as yours does).
edit:
In response to:
All I really needed was the service names in an array to then use elsewhere
$service_name = (Get-Service -computername $server_name -name sql* -exclude *sqlwriter) | select-object -expandproperty name;
or:
$service_name = (Get-Service -computername $server_name -name sql* -exclude *sqlwriter).name;
No need to invoke WMI directly.
Get-Service *sql* | sort DisplayName | out-file c:/servicelist.txt
I have a one line PowerShell script to extract list of all services running on my local machine, now, in addition to displaying "Status", "Name" and "DisplayName" I also want to display "Path to executable"
I think you'll need to resort to WMI:
Get-WmiObject win32_service | ?{$_.Name -like '*sql*'} | select Name, DisplayName, State, PathName
Update
If you want to perform some manipulation on the selected data, you can use calculated properties as described here.
For example if you just wanted the text within quotes for the Pathname, you could split on double quotes and take the array item 1:
Get-WmiObject win32_service | ?{$_.Name -like '*sql*'} | select Name, DisplayName, #{Name="Path"; Expression={$_.PathName.split('"')[1]}} | Format-List
Get-CimInstance can also be used to achieve the same, see here for the difference between CIM and WMI.
Get-CimInstance win32_service | ?{$_.Name -like '*sql*'} | select Name, DisplayName, #{Name="Path"; Expression={$_.PathName.split('"')[1]}} | Format-List
Since Get-WmiObject have been deprecated in PowerShell Core, you can use
Get-CimInstance -ClassName win32_service | ?{$_.Name -match '^sql'} | Select Name, DisplayName, State, PathName >> C:\temp\sqlservices.txt
instead.
If you don't need to check against a regular expression you can also use the -Filter parameter:
Get-CimInstance -ClassName win32_service -Filter "Name like 'sql%'" | Select Name, DisplayName, State, PathName >> C:\temp\sqlservices.txt
A variant on the WMI Query that may be faster (I just had to do this for an SCCM Client)
$SQLService=(get-wmiobject -Query 'Select * from win32_service where Name like "*SQL*"') | Select-object Name, DisplayName, State, Pathname
The other trick is to trap for the multiple SQL results if you want the path names without the Double Quotes (so you can action upon them)
$SQLService | Select-Object Name, DisplayName, State, #{Name='PathName';Expression=$_.Pathname.replace('"','')}
The big advantage to using -query in the get-wmiobject (or get-ciminstance) is the speed of processing. The older example gets a full list and then filters, whilst the latter grabs a very direct list.
Just adding in two cents :)
Cheers all!
Sean
The Energized Tech
You can also use the Regular Expression pattern and dump the result to file.
Get-WmiObject win32_service | ?{$_.Name -match '^sql'} | select Name, DisplayName, State, PathName >> C:\temp\sqlservices.txt
I'm not comfortable with the accepted answer's use of Expression={$_.PathName.split('"')[1]}} because it doesn't handle the variants of quotes, spaces, and args that I see in the data.
Here's a clunky method that does.
function PathFromServicePathName($pathName) {
# input can have quotes, spaces, and args like any of these:
# C:\WINDOWS\system32\lsass.exe
# "C:\Program Files\Realtek\Audio\HDA\RtkAudioService64.exe"
# C:\WINDOWS\system32\svchost.exe -k netsvcs -p
# "C:\Program Files\Websense\Websense Endpoint\wepsvc.exe" -k ss
# if it starts with quote, return what's between first and second quotes
if ($pathName.StartsWith("`"")) {
$pathName = $pathName.Substring(1)
$index = $pathName.IndexOf("`"")
if ($index -gt -1) {
return $pathName.Substring(0, $index)
}
else {
# this should never happen... but whatever, return something
return $pathName
}
}
# else if it contains spaces, return what's before the first space
if ($pathName.Contains(" ")) {
$index = $pathName.IndexOf(" ")
return $pathName.Substring(0, $index)
}
# else it's a simple path
return $pathName
}
Get-WmiObject win32_service | select Name, DisplayName, #{Name="Path"; Expression={PathFromServicePathName $_.PathName}} | Format-List
A variant with Format-List with full path, results in file :
Get-WmiObject win32_service | Format-Table -Wrap -AutoSize -Property State,Name,PathName | out-file C:\servicelist.txt