diskusage how to use in powershell - powershell

I am very new to powershell and writing a script which will go to each computer in windows domain and get the size of a user profile. I have tried below on a powershell script
$profileDir = "\\$computerName\c$\users\userProfile"
$fullProfile = (Get-ChildItem $profileDir -recurse -force | Measure-Object -property length -sum)
But on some computer it gives below error. The problem seems that some directories on the profile have a long path and get-ChildItem fails
Get-ChildItem : The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the directory name mu
st be less than 248 characters.
At C:\scripts\powershell\profiles.ps1:56 char:30
+ $fullProfile = (Get-ChildItem <<<< $profileDir -recurse -force | Measure-Obj
ect -property length -sum)
+ CategoryInfo : ReadError: (\\computerName...nt.IE5\RQT4K4JU:St
ring) [Get-ChildItem], PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChil
dItemCommand
##########################################################################################################################
At this point I tried using du.exe (diskusage) from SysInternals which works fine but I don't know how to take the output of du into a variable. I have below on my script
$dirSize = .\du.exe -c c:\temp |convertFrom-csv | select-object DirectorySize
write-host $dirSize
The output is
PS C:\scripts\powershell> .\profiles.ps1
#{DirectorySize=661531}
What I want the output to be like
PS C:\scripts\powershell> .\profiles.ps1
661531

What you have is a hashtable. You need to reference the item in that hashtable to get it's value. Instead of:
Write-Host $dirSize
Try:
$dirSize['DirectorySize']

Related

How to use previous command output as a parameter in Powershell?

I need to write a Powershell one-liner to do a complex task. I need it to be strictly one line because I want to run it in a Go and Python script. The task requires taking the output of the first command and use it as a parameter in the second command.
I thought it was a simple task but I am struggling with it quite a bit. For example, the below command does not work:
$obj = Get-Item . | Get-Item $obj.Root | Format-List *
Get-Item : The input object cannot be bound to any parameters for the command either because the command does not take
pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:21
+ $obj = Get-Item . | Get-Item $obj.Root | Format-List *
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (C:\Users\fhcat:PSObject) [Get-Item], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.GetItemCommand
What am I doing wrong?
Strictly one line sounds like a personal preference rather than a technical requirement.
However, you can end a statement with a semicolon or process the input via ForEach-Object
$obj = Get-Item .; Get-Item $obj.Root | Format-List *
or
Get-Item . | ForEach-Object {Get-Item $_.Root} | Format-List *

Attempting to get the sum of all file line counts in a directory

I'm attempting to get the number of lines in all files in my directory. I've tried using some kind of variable I set to 0 and looping through all the files and getting their line number.
> $i=0;ls | foreach{$i += [int](get-content $_ | measure-object -line)};$i
However, every time I try adding it to the variable I set to 0, it shoots out an odd error:
Cannot convert the "Microsoft.PowerShell.Commands.TextMeasureInfo" value of type
"Microsoft.PowerShell.Commands.TextMeasureInfo" to type "System.Int32".
At line:1 char:19
+ $i=0;ls | foreach{$i += [int](get-content $_ | measure-object -line)};$i
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : ConvertToFinalInvalidCastException
Why does this operation not work and how could it be resolved?
Is there a quicker way of obtaining the number of lines in all files in a directory?
You need to get the Lines:
$i=0;ls -File | foreach{$i += [int](get-content $_ | measure-object -line).Lines};$i
I've also added the -File switch to ls/gci to only get the content of files.
Version with aliases expanded:
$i=0;Get-ChildItem -File | ForEach-Object {$i += [int](Get-Content $_ | Measure-Object -line).Lines};$i

Trying to Create a script that will get my filtered list of Get-Adcomputer then run a command on each

Firstly,
I am very new to powershell. Everytime I think i get the logic i go WTF.. If this was bash it would be so easy etc..
what am I trying to do exactly ...
Get all computers from AD that Meet the Xiopwb* criteria. Once i have the list I need to change the permissions on the \\Xiopwb20\Nsiwebroot Directory to ONLY INCLUDE Domain Administrators and A Security group "webadmins"
My Logic:
Get all computers from AD that meet Xio*PWB*
Take just the NAME of objects in that list
for ever "name" in that list do Get-ACL \\Name from list\Nsiwebroot
remove *
add user / group.
What I have:
PS C:\Windows\system32> Get-ADComputer -filter * | Where-Object {$_.Name -like "xiopwb*"} | Select Name | ForEach-Object { Get-Acl \\$_.Name\nsiwebroot}
all up to the "ForEach" works... I get just the names of the PC's that I need etc..
Simple as possible I don't need a 100 line script.
Thanks
** update **
it is double \ its just not showing it... no idea why
Looks like it is doing what I want to a degree. However its spitting out the format funky. #{Name=XIOPWB09}
PS C:\Windows\system32> Get-ADComputer -filter * | Where-Object {$_.Name -like "xiopwb*"} | Select Name | ForEach-Object {get-acl "\\$_\D$\nsiwebroot"}
get-acl : Cannot find path '\#{Name=XIOPWB09}\D$\nsiwebroot' because it does not exist.
At line:1 char:99
+ ... opwb*"} | Select Name | ForEach-Object {get-acl "\$_\D$\nsiwebroot"}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
+ FullyQualifiedErrorId : GetAcl_PathNotFound_Exception,Microsoft.PowerShell.Commands.GetAclCommand
get-acl : Cannot find path '\#{Name=XIOPWB06}\D$\nsiwebroot' because it does not exist.
At line:1 char:99
+ ... opwb*"} | Select Name | ForEach-Object {get-acl "\$_\D$\nsiwebroot"}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
+ FullyQualifiedErrorId : GetAcl_PathNotFound_Exception,Microsoft.PowerShell.Commands.GetAclCommand
"Select Name" returns an Object with Table Header Name. "Select -ExpandProperty Name" is What needed here, which will convert it o String.
Regards,
kvprasoon

260 Character Limit, Get-ChildItem

I understand there is a 260 character limit for win32, but I am curious as to why my code is half working. See below.
$Age_of_Files = -30
$Path = '\\share\d$\share'
$Age_of_Files = -30
$Current_Date = Get-Date
$Del_date = $Current_Date.AddDays($Age_of_Files)
$post = "<BR><i>Report generated on $((Get-Date).ToString())</i>"
Get-ChildItem $Path -Recurse |
Where-Object { $_.LastWriteTime -lt $Del_date} |
Select Name, FullName, LastWriteTime
$Data | ConvertTo-HTML -PreContent $pre -PostContent $post | Out-File $Report
Invoke-Item $Report
Read-Host 'Have you checked the Output File...Ok to Continue with Delete?' | Out-Null
This will check my network share with no problem and give me no errors, although there are many directories longer then 260 characters but I also want to export this as a HTML file, so If I change this line of code.
$Data = Get-ChildItem $Path -Recurse |
Where-Object { $_.LastWriteTime -lt $Del_date } |
Select Name, FullName, LastWriteTime
It then does not recurse through the directories, and gives me the character limit error.
Is there a way around this? As apart from exporting it to HTML and adding in the actual delete command I think I am nearly there.
You can turn on long paths in Windows 10. There's a gpo.
https://www.howtogeek.com/266621/how-to-make-windows-10-accept-file-paths-over-260-characters/
This is a limitation of the Win32 API (see also). There's a PowerShell Module that supposedly works around the issue (haven't used it myself, though).
A common workaround is to shorten the path by substing the longest accessible path to a drive letter
& subst X: C:\longest\parent\folder
working on drive X:, then deleting the temporary drive afterwards:
& subst X: /d
For network paths use net use to the same end:
& net use X: \\server\share\longest\parent\folder
...
& net use X: /d

Count & Average files in a folder

Here is my code:
$folders = gci C:\NuGetRoot\NugetServer -Directory
foreach ($folder in $folders) {
#{ServerName=$env:COMPUTERNAME;
ProjectGroupID = $folder.Name;
NuGetPackageCount = (gci $folder.FullName\Packages -Include '*.txt') | %{$_.Size}.Count;
AverageSize = gci $folder.FullName -Recurse -Filter *.txt | measure-object -property length -average;
} | Export-Csv -Path d:\monitoring\NugetStatistics -NoTypeInformation -Append
}
I am looping through the folders in C:\NuGetRoot\NugetServer and then displaying the server name, the folder name (ProjectGroupID), package count of files ending in .nupkg in the 'packages folder for each folder, and the avg size of all of the files that are contained within the "packages" folder for each folder. The server name and ProjectGroupID display correctly. The count and average one aren't. I get the error:
gci : Second path fragment must not be a drive or UNC name. Parameter name:
path2
At line:5 char:30
+ NuGetPackageCount = (gci $folder.FullName\packages -Include '*.nupkg') | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (D:\apps\nuget.ciodev.accenture.com:String) [Get-ChildItem], ArgumentException
+ FullyQualifiedErrorId : DirArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand*
I think it has something to do with the "\packages", because if I remove that it works, but I need to navigate to that folder because that's where the files are.
Instead of running Get-ChildItem 3 times like you are, you could run it once for all *.nupkg files, group them by the project they're associated with, and the grouping objects would have most the info you want right there. Consider this alternative:
$BasePath = "C:\NuGetRoot\NugetServer"
$folders = gci "$BasePath\*\Packages\..\*.nupkg" -Recurse
$(foreach ($folder in $folders|group #{e={$_.fullname.split('\')[0..3] -join '\'}}) {
[pscustomobject]#{
ServerName=$env:COMPUTERNAME
ProjectGroupID = Split-Path $folder.Name -Leaf
NuGetPackageCount = $folder.group.Where({$_.Directory -match 'Packages'}).count
AverageSize = $folder.Group | measure-object -property length -average | Select -Expand Average
}
}) | Export-CSV d:\monitoring\NugetStatistics -NoType -Append
I did have to be a little creative on the Count line's RegEx match to make sure I only got things within the Packages folder, but it works just fine. I created a test set of files:
C:\Temp\Test\ProjectA\Packages\File2.nupkg
C:\Temp\Test\ProjectA\Packages\File3.nupkg
C:\Temp\Test\ProjectA\File1.nupkg
C:\Temp\Test\ProjectA\File2.nupkg
C:\Temp\Test\ProjectA\File3.nupkg
C:\Temp\Test\ProjectB\Packages\File2.nupkg
C:\Temp\Test\ProjectB\Packages\File3.nupkg
C:\Temp\Test\ProjectB\File1.nupkg
C:\Temp\Test\ProjectC\Packages\File2 - Copy.nupkg
C:\Temp\Test\ProjectC\Packages\File2.nupkg
C:\Temp\Test\ProjectC\Packages\File3 - Copy.nupkg
C:\Temp\Test\ProjectC\Packages\File3.nupkg
C:\Temp\Test\ProjectC\File1.nupkg
C:\Temp\Test\ProjectC\File3.nupkg
When I ran the above script against the $BasePath of C:\Temp\Test I got these results:
ServerName ProjectGroupID NuGetPackageCount AverageSize
---------- -------------- ----------------- -----------
MININT-BMOSR3C ProjectA 2 161.2
MININT-BMOSR3C ProjectB 2 155.333333333333
MININT-BMOSR3C ProjectC 4 157.666666666667
I did want to point out that you run the Count against the Packages folder, but you run the AverageSize against the entire folder. You may want to add the .Where() statement from the Count line to the Average line if you only want files in the Packages folder for your average.
This should speed things up though since it only runs Get-ChildItem once, not once, and then 2 additional times for each folder, and it gets you the same data.