I am writing a script for work and trying to determine why my code is showing errors. I am new to this coding and want to understand what is wrong.
The errors I get are from the tag .... PC listings in my .txt file.
Ex: Get-Content : Cannot find path 'F:\tag 77909' because it does not exist.
My confusion is that when I write-host after the .Replace code it prints correctly
Ex:You cannot call a method on a null-valued expression. + $Notags =$PC.Replace <<<< ("tag ", "PC")
+ CategoryInfo : InvalidOperation: (Replace:String) [], RuntimeEx
ception
+ FullyQualifiedErrorId : InvokeMethodOnNull
Last error I get is that it only prints out the last PC.... ID in my .txt file listing??? I am unsure why given I have a foreach loop
**MY CODE SO FAR:**
Import-Module activedirectory
$compImports = Get-Content "C:\Temp\temp\input.txt"
$groupExport = "C:\temp\temp\output.txt"
Clear-Content $groupExport
$Header = "PC Name" + "|" + "Group Name" + "|" + "Group Description"
#Write header
$Header | Out-File $groupExport -Append
#get PC tag listing
$PCs = Get-Content $compImports
#For loop to change all "tag " to "PC"
foreach($PC in $PCS)
{
$Notags =$PC.Replace("tag ", "PC")
}
#loop to get information and print it out
foreach ($Notag in $Notags) {
$computerobj = Get-ADComputer $Notag -Properties memberof
$computerobj.memberof | ? {$_ -match '^CN=APP.*'} `
| % {get-adgroup $_ -Properties name, description} | `
% {$computerobj.Name + "|" + $_.name + "|" + $_.description `
| Out-File $groupExport -Append}
}
I see at least one issue here
$compImports = Get-Content "C:\Temp\temp\input.txt"
...
$PCs = Get-Content $compImports
You are calling Get-Content twice which would generate the error you are seeing most likely.
Could be simplified as
$PCs = Get-Content "C:\Temp\temp\input.txt"
Your other error should go away as a result since $PCs should contain real data at that point.
Related
Trying to get total jobs printed.
It works fine for one printer:
cls
$WebResponse = Invoke-WebRequest "10.240.16.156/server/JOBLOG.htm"
$Total = $WebResponse.AllElements | Select innerText | Select -Index '12'
$Total
Output:
innerText
---------
Total Jobs Printed:737
But I need to get that information from five hundred printers, that IP's I have in .csv file:
"PortName"
"10.240.8.27"
"10.240.9.87"
"10.240.19.81"
...
Tried to import IP from CSV, but it only uses last IP from .csv and cannot build a valid url:
cls
$Printers = Import-Csv -Path C:\path\to\csv\_printers.csv
$Url = "http://$PortName/server/JOBLOG.htm"
$WebResponse = ForEach ($PortName in $Printers) {Invoke-WebRequest $Url}
$Total = $WebResponse.AllElements | Select innerText | Select -Index '12'
ForEach ($PortName in $Printers) {
$Total
}
Output:
Invoke-WebRequest : Cannot bind parameter 'Uri'. Cannot convert value "http://#{PortName=10.240.11.86}/server/JOBLOG.htm" to type "System.Uri". Error: "Invalid URI: The hostname could not
be parsed."
At line:4 char:68
+ ... bResponse = ForEach ($PortName in $Printers) {Invoke-WebRequest $Url}
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WebRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Any help?
Thanks
I'm guessing you're looking for something like this:
Import-Csv -Path C:\path\to\csv\_printers.csv | ForEach-Object {
$Url = "http://{0}/server/JOBLOG.htm" -f $_.PortName
[pscustomobject]#{
URL = $Url
Response = (Invoke-WebRequest $Url).AllElements.InnerText[12]
}
}
The error message is actually showing you the object being converted to a string (#{PortName=10.240.11.86}):
.. Cannot convert value "http://#{PortName=10.240.11.86}/server/JOBLOG.htm" ..
You need to expand the PortName property from your object to get the value (only the IP), hence the use of $_.PortName in my example.
I am trying to get the real names of each user in an AD group, I have created it to the point of getting the output to show the User IDs of each member in the group but then trying to do a net user $_ /domain on each user in the .txt file it gives me errors like there is nothing there. Before the onslaught of "why dont you just use Get-AD*" I understand that its out there, but we cannot install that module here. I need something other people can use without installing things.
I have tried a few ways to approach this and the below code is the part of the script that doesnt seem to be working correctly. I have the other way I tried it commented out but left it there as another possible starting point.
function Return-DropDown {
$Choice = $DropDown.SelectedItem.ToString()
if ($Choice)
{
net group $Choice /domain > C:\Temp\RawOut.txt
$UserID = Get-Content 'C:\Temp\RawOut.txt'
$UserID[($UserID.IndexOf('-------------------------------------------------------------------------------') + 1) .. ($UserID.IndexOf('The command completed successfully.') -1)] > C:\Temp\RawIDs.txt
Start C:\Temp\RawIDs.txt
Remove-Item C:\Temp\RawOut.txt
Get-Content -path C:\Temp\RawIDs.txt | ForEach-Object {net user $_ /domain | findstr "Full Name"} >> C:\Temp\$Choice+RealNames.txt
#$RealNames = Get-Content -path C:\Temp\RawIDs.txt
#ForEach ($_ in $RealNames)
#{
# net user $_ /domain >> C:\Temp\$Choice+1.txt
# }
}
}
What I am getting back is:
net : The syntax of this command is:
At C:\Users\MyID\OneDrive - MyCompany\AD Group DropDown.ps1:34 char:64
+ ... path C:\Temp\RawIDs.txt | ForEach-Object {net user $_ /domain} >> C:\ ...
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The syntax of this command is::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
NET USER
[username [password | *] [options]] [/DOMAIN]
username {password | *} /ADD [options] [/DOMAIN]
username [/DELETE] [/DOMAIN]
username [/TIMES:{times | ALL}]
username [/ACTIVE: {YES | NO}]
Let me know any advice for getting this function to work.
Thank you to #LotPings for helping me out with finding a solution.
I discovered (through looking at a post LotPings commented) that I was getting the output in a format that was causing an error. My txt file was formatted:
User1 User2 User3
User4 User5 User6
...
And it was trying to take the full line User1 User2 User3 as the variable. Which was obviously not working. with using a -replace and -split to get the format right for my variable and it's working now.
function Return-DropDown {
$Choice = $DropDown.SelectedItem.ToString()
if ($Choice)
{
net group $Choice /domain > C:\Temp\RawOut.txt
$UserID = Get-Content 'C:\Temp\RawOut.txt'
$UserID[($UserID.IndexOf('-------------------------------------------------------------------------------') + 1) .. ($UserID.IndexOf('The command completed successfully.') -1)] > C:\Temp\RawIDs.txt
#Start C:\Temp\RawIDs.txt
Remove-Item C:\Temp\RawOut.txt
$results = Get-Content -path C:\Temp\RawIDs.txt
foreach($result in $results) {
($result -replace '\s+',',') -split ',' | ? { $_ } >> 'C:\temp\users.txt'
}
Get-Content -path C:\Temp\users.txt | ForEach-Object {net user $_ /domain | findstr "Full Name"} >> C:\Temp\$Choice.txt
Remove-Item C:\Temp\users.txt
Remove-Item C:\Temp\RawIDs.txt
Start C:\Temp\$Choice.txt
}
}
I am trying to fetch OperatingHours tag details for all the Azure VirtualMachines and Azure SqlDatabases.
Following are the possibility for appID in a resource and the values I need to print in output correspondingly:
If OperatingHours tag itself is not present in any resource then display "Tag not present"
if OperatingHours tag is present but contains null or empty string then display "NULL/EMPTY"
if OperatingHours tag is present with any other value then display that value.
Do I need to take care of option (2) separately or is it like printing any normal value of the OperatingHours.
After long efforts I have created following script:
$ErrorOccured = $false
$resources = Get-AzureRmResource |
Where-Object {($_.ResourceType -eq "Microsoft.Compute/virtualMachines") -or ($_.ResourceType -eq "Microsoft.Sql/servers/databases")} |
foreach {
new-object psobject -Property #{
ResourceName = $_.ResourceName;
ResourceType = $_.ResourceType;
OperatingHours= try {
$ErrorActionPreference = 'SilentlyContinue';
($_ | select -expand Tags).OperatingHours; }
catch {
$ErrorOccured = $true ; }
if ($ErrorOccured)
{ "Tag not present" }
else {
($_ | select -expand Tags).OperatingHours;
$ErrorOccured = $false };}
}
$resources | Format-Table
When running this script, I am receiving following error:
At line:13 char:58
+ }
+ ~
The hash literal was incomplete.
At line:20 char:2
+ }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : IncompleteHashLiteral
If I replace the OperatingHours statement with following code then the script is running with success. But in doing so, I am not able to satisfy the option (1) mentioned above.
Operating Hours = if (!($_ | select -expand Tags).OperatingHours)
{"Tag not present"}
else {($_ | select -expand Tags).OperatingHours} ;
Please advise me on how to correct this and get the required output.
Thanks
After alot of hit and trial and rigorous testing, I found what I was looking for:
OperatingHours = if ( ($_ | select -expand Tags).OperatingHours -ieq $null )
{"TAG NOT PRESENT"}
elseif ( ($_ | select -expand Tags).OperatingHours -ieq '')
{"NULL/EMPTY"}
else
{($_ | select -expand Tags).OperatingHours } ;
I replaced the OperatingHours statement in original script to above.
The solution looks easy and after finding it I was like how could I miss that earlier, but that's what learning process is all about, right ?
I have a series of documents that are going through the following function designed to count word occurrences in each document. This function works fine outputting to the console, but now I want to generate a text file containting the information, but with the file name appended to each word in the list.
My current console output is:
"processing document1 with x unique words occuring as follows"
"word1 12"
"word2 8"
"word3 3"
"word4 4"
"word5 1"
I want a delimited file in this format:
document1;word1;12
document1;word2;8
document1;word3;3
document1;word4;4
document1;word1;1
document2;word1;16
document2;word2;11
document2;word3;9
document2;word4;9
document2;word1;13
While the function below gets me the lists of words and occurences, I'm having a hard time figuring out where or how to insert the filename variable so that it prints at the head of each line. MSDN has been less-than helpful, and most of the places I try to insert the variable result in errors (see below)
function Count-Words ($docs) {
$document = get-content $docs
$document = [string]::join(" ", $document)
$words = $document.split(" `t",[stringsplitoptions]::RemoveEmptyEntries)
$uniq = $words | sort -uniq
$words | % {$wordhash=#{}} {$wordhash[$_] += 1}
Write-Host $docs "contains" $wordhash.psbase.keys.count "unique words distributed as follows."
$frequency = $wordhash.psbase.keys | sort {$wordhash[$_]}
-1..-25 | %{ $frequency[$_]+" "+$wordhash[$frequency[$_]]} | Out-File c:\out-file-test.txt -append
$grouped = $words | group | sort count
Do I need to create a string to pass to the out-file cmdlet? is this just something I've been putting in the wrong place on the last few tries? I'd like to understand WHY it's going in a particular place as well. Right now I'm just guessing, because I know I have no idea where to put the out-file to achieve my selected results.
I've tried formatting my command per powershell help, using -$docs and -FilePath, but each time I add anything to the out-file above that runs successfully, I get the following error:
Out-File : Cannot validate argument on parameter 'Encoding'. The argument "c:\out-file-test.txt" does not bel
ong to the set "unicode,utf7,utf8,utf32,ascii,bigendianunicode,default,oem" specified by the ValidateSet attribute. Sup
ply an argument that is in the set and then try the command again.
At C:\c.ps1:39 char:71
+ -1..-25 | %{ $frequency[$_]+" "+$wordhash[$frequency[$_]]} | Out-File <<<< -$docs -width 1024 c:\users\x46332\co
unt-test.txt -append
+ CategoryInfo : InvalidData: (:) [Out-File], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.OutFileCommand
I rewrote most of your code. You should utilize objects to make it easier formatting the way you want. This one splits on "space" and groups words together. Try this:
Function Count-Words ($paths) {
$output = #()
foreach ($path in $paths) {
$file = Get-ChildItem $path
((Get-Content $file) -join " ").Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries) | Group-Object | Select-Object -Property #{n="FileName";e={$file.BaseName}}, Name, Count | % {
$output += "$($_.FileName);$($_.Name);$($_.Count)"
}
}
$output | Out-File test-out2.txt -Append
}
$filepaths = ".\test.txt", ".\test2.txt"
Count-Words -paths $filepaths
It outputs like you asked(document;word;count). If you want documentname to include extension, change $file.BaseName to $file.Name . Testoutput:
test;11;1
test;9;2
test;13;1
test2;word11;5
test2;word1;4
test2;12;1
test2;word2;2
Slightly different approach:
function Get-WordCounts ($doc)
{
$text_ = [IO.File]::ReadAllText($doc.fullname)
$WordHash = #{}
$text_ -split '\b' -match '\w+'|
foreach {$WordHash[$_]++}
$WordHash.GetEnumerator() |
foreach {
New-Object PSObject -Property #{
Word = $_.Key
Count = $_.Value
}
}
}
$docs = gci c:\testfiles\*.txt |
sort name
&{
foreach ($doc in dir $docs)
{
Get-WordCounts $doc |
sort Count -Descending |
foreach {
(&{$doc.Name;$_.Word;$_.Count}) -join ';'
}
}
} | out-file c:\somedir\wordcounts.txt
Try this:
$docs = #("document1", "document2", ...)
$docs | % {
$doc = $_
Get-Content $doc `
| % { $_.split(" `t",[stringsplitoptions]::RemoveEmptyEntries) } `
| Group-Object `
| select #{n="Document";e={$doc}}, Name, Count
} | Export-CSV output.csv -Delimiter ";" -NoTypeInfo
If you want to make this into a function you could do it like this:
function Count-Words($docs) {
foreach ($doc in $docs) {
Get-Content $doc `
| % { $_.split(" `t",[stringsplitoptions]::RemoveEmptyEntries) } `
| Group-Object `
| select #{n="Document";e={$doc}}, Name, Count
}
}
$files = #("document1", "document2", ...)
Count-Words $files | Export-CSV output.csv -Delimiter ";" -NoTypeInfo
Being new to powershell and used to oneliners in unix I find powershell strange. The below code gives me a "too many pipes" type of error. Can anyone tell me what I am doing wrong. My last step will be to add code that adds permission if not found in the else block.
[PS] C:\Windows\system32>(Get-mailbox -identity moh | select alias, distinguishedname) | foreach-object -process { if($_.distinguishedname -match "HK1|VO[1-9]") { $alias = $_.alias; get-mailboxfolderstatistics -identity $alias | Where {$_.FolderType -eq 'Calendar'} | %{ $calpath = $_.folderpath.substring(1); Get-MailboxFolderPermission -Identity $alias":\"$calpath -User iTell | %{ if($_.AccessRights -eq 'Editor') { write-host "Editor!" } else { write-host $_.AccessRights }} } } }
I get the following error.
Pipeline not executed because a pipeline is already executing. Pipelines cannot be executed concurrently.
+ CategoryInfo : OperationStopped: (Microsoft.Power...tHelperRunspace:ExecutionCmdletHelperRunspace) [], PSInvalidOperationException
+ FullyQualifiedErrorId : RemotePipelineExecutionFailed
Got it. Had to encapsulate blocks of code with parenthesis. But I thought the pipe block was just some sort of a write lock. In here I was only getting data and hence ought to be able to read from the streams.