Very very new to PowerShell
First off all I'd like to give the scenario what I'm trying to do.
We have a SharePoint site and users can add their OneNote books to this SharePoint site. The URL's to the SharePoint site is now changing. So I'm exporting the registry entries to a text file, change the part of the path to the new one, and add the new URL's to the registry.
The problem I'm having is when I export the URL's (because of the way I'm exporting for sure) the text file has a string called "Value" and the URL's are under it.
So the first question is how do I write the values to a text file where only the values get written (in this case the URL's)
And second question is how do I write these changed values back to the registry?
Every URL is a new "string" and the names start with 1, 2, 3 and so on.
Thank you everyone for their time in advance.
# Create a new folder if not exist file
$Folder = "C:\backup"
if(-not(Test-Path $Folder)){
New-Item -Path $Folder -ItemType Directory
}
# Start Logging
Start-Transcript -Path "C:\backup\onenote.log"
#Set Variables
$OneNoteBooks = "C:\backup\onenotenotebooks.txt"
$NewPath = '//newpath.com/'
# Delete the existing file if exists
If (Test-Path $OneNoteBooks){Remove-Item $OneNoteBooks}
# Create a new text file
New-Item -Path $OneNoteBooks -ItemType File
# Exporting OneNote SharePoint Notebooks and Correcting them to the new URL
Write-Host "Exporting OneNote SharePoint Notebooks and Correcting them to the new URL"
Push-Location
Set-Location 'HKCU:\Software\Microsoft\Office\14.0\Onenote\opennotebooks'
Get-Item . | Select-Object -ExpandProperty Property | ForEach-Object {
New-Object PSobject -Property #{"property"=$_;
"Value" = (Get-ItemProperty -Path . -Name $_).$_}} | Format-Table Value -AutoSize | Out-File $OneNoteBooks
Pop-Location
$ReplaceURL = Get-Content -Path $OneNoteBooks
ForEach-Object{
$ReplaceURL -replace "`//.*?(`/)", $NewPath | Out-File $OneNoteBooks
}
# Add Changed URL's to the registry
ForEach-Object {
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name PowerShellPath -PropertyType String -Value $PSHome
# Stop Logging
Stop-Transcript
Where to start? How about with the fact that in your ForEach loop you create an object with two properties, and then use Format-Table (alias FT used), and select one of the two properties making the whole object pointless... instead just get and output the value that you want.
Get-Item . | Select-Object -ExpandProperty Property | ForEach-Object {Get-ItemProperty -Path . -Name $_).$_} | Out-File $OneNoteBooks
Or better yet, use the built in functions of the Item from your Get-Item to get and set your values in a ForEach loop. Try this out...
# Create a new folder if not exist file
$Folder = "C:\backup"
if(-not(Test-Path $Folder)){
New-Item -Path $Folder -ItemType Directory
}
# Start Logging
Start-Transcript -Path "C:\backup\onenote.log"
#Set Variables
$OneNoteBooks = "C:\backup\onenotenotebooks.txt"
$NewPath = '//newpath.com/'
$OldPath = '//oldpath.com/'
$SitesChangingMask = "$([regex]::escape("$oldpath"))(nibremv|finance|sites/procurement|Comm|Departments/NITAS|ro|nitd|cnibr|communities/sig)/?"
# Delete the existing file if exists
If (Test-Path $OneNoteBooks){Remove-Item $OneNoteBooks}
# Create a new text file
New-Item -Path $OneNoteBooks -ItemType File
# Exporting OneNote SharePoint Notebooks and Correcting them to the new URL
"Exporting OneNote SharePoint Notebooks and Correcting them to the new URL"
Push-Location
Set-Location 'HKCU:\Software\Microsoft\Office\14.0\Onenote\opennotebooks'
$OneNoteReg = Get-Item .
$OneNoteReg.Property | ForEach-Object {
$CurrentValue = $OneNoteReg.GetValue($_)
$NewValue = if($CurrentValue.ToString() -match $SitesChangingMask){$CurrentValue.ToString() -replace "$OldPath", $NewPath}else{$CurrentValue.ToString()}
Set-ItemProperty 'HKCU:\Software\Microsoft\Office\14.0\Onenote\opennotebooks' -Name $_ -Value $NewValue
[PSCustomObject][Ordered]#{
"Value Name"=$_
"Original Value"=$CurrentValue
"Updated Value"=$NewValue
}
} | FT -AutoSize | Out-File $OneNoteBooks
Pop-Location
# Stop Logging
Stop-Transcript
I also changed your RegEx pattern for your replace since the old one didn't seem right. For example, in HTTP://www.microsoft.com/powershell it would update that string to read http://www.microsoft.com//newsite.com/powershell and I don't think that was your intention.
When saving data to a file, skip using the Format commands. You could use a CSV file here instead:
Get-Item . | Select-Object -Exp Property | ForEach-Object {
New-Object PSCustomObject -Property #{"Property"=$_;"Value"=(Get-ItemProperty . -Name $_).$_}} |
Export-Csv $OneNoteBooks
Modify the file, then re-read it like so:
$props = Import-Csv $OneNoteBooks
Then you can access the property names and values like so:
$props.Property[0]
$props.Value[0]
..
Of course, you don't really need to go to a file to modify the values. You could do it in memory:
$props = Get-Item . | Select-Object -Exp Property | ForEach-Object {
New-Object PSCustomObject -Property #{"Property"=$_;"Value"=(Get-ItemProperty . -Name $_).$_}}
$props = $props | Foreach {$_.Value = $_.Value -replace 'pattern','replacement'}
If you would prefer to create a .reg file that you can then import try this:
"Windows Registry Editor Version 5.00`n" > c:\onenotebooks.reg
"[$($pwd.ProviderPath)]" >> c:\onenotebooks.reg
Get-Item . | Select-Object -Exp Property |
ForEach-Object { "`"$_`"=`"$((Get-ItemProperty . -Name $_).$_)`"" } >> c:\onenotebooks.reg
The problem is in this line of code.
"Value" = (Get-ItemProperty -Path . -Name $_).$_}} | Format-Table Value -AutoSize | Out-File $OneNoteBooks
I'd suggest removing the format-table. If its not showing you everything then try this:
"Value" = (Get-ItemProperty -Path . -Name $_).$_}} | Foreach-Object {$_.Value} | Out-File $OneNoteBooks
Related
I've researched this and haven't been able to come up with a solid solution. Basically, I have a separate hard drive containing thousands of music files. I have a CSV list with the names of all the files that should be in the hard drive. Example:
My List
I want to be able to test if each of the files on my list exist in the hard drive, and if not, export it to a separate "missing files" list. The thing is each of the files in the hard drive exist under multiple folders.
As my script is now, I am trying to test if the path exists by using join-path. Here is my code right now - it's returning all of the files in the directory instead of just the missing files:
$documents = 'C:\Users\Me\Documents\ScriptTest'
$CSVexport = 'C:\Users\Me\Documents\ScriptTest\TestResults.csv'
$obj = #()
Write-host "`n_____Results____`n" #Write the results and export to a CSV file
$NewCsv = Import-CSV -Path 'C:\Users\Me\Documents\ScriptTest\Test.csv' |
Select-Object ID,'File Path' |
ForEach-Object {
if (!(Test-Path (Join-Path $documents $_.'File Path'))){
write-host "`n$($_.'File Path') is missing from the folder.`n"
$ObjectProperties = #{
ID = $_.ID
'File Path' = $_.'File Path'
}
$obj += New-Object PSObject -Property $ObjectProperties
}
}
$obj | export-csv $CSVexport -NoTypeInformation
How do I account for the sub-directories that vary with each file?
Edit - Resolved
$myFolder = 'C:\Users\Me\Documents\ScriptTest'
$CSVexport = 'C:\Users\Me\Documents\ScriptTest\Results.csv'
$csvPath = 'C:\Users\Me\Documents\ScriptTest\Test.csv'
$FileList = Get-ChildItem $myFolder -Recurse *.wav | Select-Object -ExpandProperty Name -Unique
Import-CSV -Path $csvPath |
Where-Object {$FileList -notcontains $_.'File Path'} |
export-csv $CSVexport -NoTypeInformation
You could generate a list of filenames from the recursed folders, then check if the file is in that list.
$documents = 'C:\Users\Me\Documents\ScriptTest'
$CSVexport = 'C:\Users\Me\Documents\ScriptTest\TestResults.csv'
$FileList = Get-ChildItem $documents -Recurse |
Where-Object { -not $_.PSIsContainer } |
Select-Object -ExpandProperty Name -Unique
Import-CSV -Path 'C:\Users\Me\Documents\ScriptTest\Test.csv' |
Where-Object {$FileList -notcontains $_.File} |
Export-CSV $CSVexport -NoTypeInformation
Edit: Answer updated to work with PowerShell 2.0 with suggestions from Bruce Payette and mklement0
I am trying to export Groupmembers list from azuread, my whole script works fairly well, but I need each new line in the final file to have the name of the file it is importing from (as well as the content it is importing)
the part of the script i am using to do this is as follows
(found this code here
Merging multiple CSV files into one using PowerShell)
get-childItem "C:\Users\user\Documents\Azure\Intune\management\*.csv" | foreach {
$filePath = $_
$lines = $lines = Get-Content $filePath | Select -Skip 1
$linesToWrite = switch($getFirstLine) {
$true {$lines}
$false {$lines | Select -Skip 1}
}
$getFirstLine = $false
Add-Content "C:\Users\user\Documents\Azure\Intune\management\master_list.csv" $linesToWrite
}
I would probably do something like this:
$files = Get-ChildItem -Path "C:\Users\user\Documents\Azure\Intune\management\*.csv"
ForEach ($file in $files) {
Import-Csv -Path $File.FullName |
Select-Object -Property *, #{n='FileName';e={$file.Name}} |
Export-Csv -Path "C:\Users\user\Documents\Azure\Intune\management\master_list.csv" -NoTypeInformation -Append
}
Note that you need v3 or later of PowerShell to get the -Append flag for Export-Csv.
Another way to do it. This way would be potentially memory intensive if the files are large but I like the method and it fits well with the way my brain works.
$result = New-Object System.Collections.ArrayList
foreach($file in Get-ChildItem 'C:\Users\User\Documents\Azure\InTune\Management\*.csv'){
$result.AddRange((Import-CSV $file | Add-Member -InputObject $_ -Name 'File' -MemberType NoteProperty -Value $file.Name))
}
$result | Export-CSV 'C:\Users\user\Documents\Azure\Intune\management\master_list.csv' -NoTypeInformation
I think that would be version agnostic but I always lose track of which features happen in which version. Actually I think Add-Member would put it at v3+.
I wrote a script in powershell to locate the files in share drives which takes the names of files from a .txt file. The script is as below.
$Files= Get-Content lock.txt
foreach ($File in $Files) {
get-childitem -path Z:\lonmgb003_2 -Name $File -Recurse
}
Could someone help me with identifying size of file along with path. Thanks in advance.
The -Name parameter is a switch - it doesn't take an argument - and it causes Get-ChildItem to output just the file name and nothing else. The $File argument is instead being bound to the -Filter parameter.
Remove the -Name parameter and then use the Select-Object cmdlet to select just the path and size.
Since you have all the file names in an array already, you might as well use the -Include parameter to retrieve them all at once:
Get-ChildItem -Path Z:\lonmgb003_2 -Include $Files -Recurse |Select FullName,Length
You would need the Length and FullName properties of the files. You can do something like this.
$array= #()
$Files= Get-Content lock.txt
foreach ($File in $Files)
{
get-childitem -path Z:\lonmgb003_2 -Recurse | ?{$_.Name -like $File}
$obj = New-Object PSObject
$Size = [Math]::Round((Get-ChildItem -Recurse $_.FullName | Measure-Object Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB, 2)
$obj | Add-Member -MemberType NoteProperty -Name "Path" $_.FullName
$obj | Add-Member -MemberType NoteProperty -Name "SizeinMB" $Size
$array +=$obj
}
$array | select Path, SizeinMB
What i have done is create a custom PS object that will store the FullName(precisely path) and Size of all the files. The use of -Name property doesn't help as it would just return you file name as a string and not the name as file (whose property you can use). Hence, a where-Object to match the file names in the text file. After your operation is done, the desired output is stored in an array named $array.
Is it possible to use $SecretFolder from the else statement in future Iterations if the company is the same. E.g. Multiple users exist on the list from one company but they all need to have a link generated for 1 folder for the company to access.
#Location of original dataset
$csv = Import-Csv c:\export.csv
#loops through every line of the csv
Foreach ($line in $csv){
#Generate random folder name (8 Characters long)
$SecretFolder = -join ((48..57) + (97..122) | Get-Random -Count 8 | % {[char]$_})
#Create URL
$url = "www.website.com.au/2017Rates/$SecretFolder"
#Test: Has the company already had a folder created
if (Get-Variable $line.CompanyName -Scope Global -ErrorAction SilentlyContinue)
{
#Append URL to CSV for a person who already has a company folder
$report =#()
$report += New-Object psobject -Property #{CompanyName=$line.CompanyName;FirstName=$line.FirstName;LastName=$line.LastName;EmailAddress=$line.EmailAddress;'Letter Type'=$line.'Letter Type';URL=$URL}
$report | export-csv testreporting.csv -Append
}
else
{
#Create Folder with Random Cryptic name
mkdir C:\Users\bford\test\$SecretFolder
#Copy item from FileLocation in CSV to SecretFolder Location
Copy-Item -Path $line.FileLocation -Destination c:\users\bford\test\$SecretFolder -Recurse -ErrorAction SilentlyContinue
#Create Variable for Logic test with the Name CompanyName
New-Variable -Name $line.CompanyName
#Append csv with the updated details
$S_report =#()
$S_report += New-Object psobject -Property #{CompanyName=$line.CompanyName;FirstName=$line.FirstName;LastName=$line.LastName;EmailAddress=$line.EmailAddress;'Letter Type'=$line.'Letter Type';URL=$url}
$S_report | export-csv testreporting.csv -Append
}
}
#Cleanup remove all the variables added
Remove-Variable * -ErrorAction SilentlyContinue
Do you have any reason to think it's impossible? Yeah it's possible, you should Google hashtables and find that they do everything you're trying to do with get-variable, only way better.
But your question amounts to "how do I rewrite my script so it works?" and rewriting your script to me means getting rid of the duplicate #()+= triple lines, the mystery numbers, the global variables, and the extra variables and the if/else, and it ends up a completely different script altogether.
A completely different, and mostly untested, script:
# import and group all people in the same company together
# then loop over the groups (companies)
Import-Csv -Path c:\export.csv |
Group-Object -Property CompanyName |
ForEach-Object {
# This loop is once per company, make one secret folder for this company.
$SecretFolder = -join ( [char[]]'abcdefghijklmnopqrstuvwxyz1234567890' | Get-Random -Count 8 )
New-Item -ItemType Directory -Path "C:\Users\bford\test\$SecretFolder"
# Loop through all the people in this company, and copy their files into this company's secret folder
$_.Group | ForEach-Object {
Copy-Item -Path $_.FileLocation -Destination c:\users\bford\test\$SecretFolder -Recurse -ErrorAction SilentlyContinue
}
# Output each person in this company with just the properties needed, and a new one for this company's URL
$_.Group | Select-Object -Property CompanyName , FirstName,
LastName, EmailAddress, 'Letter Type',
#{Name='Url'; Expression={"www.website.com.au/2017Rates/$SecretFolder"}}
} | Export-Csv -Path testreporting.csv -NoTypeInformation
But to edit your script to do what you want, use a hashtable, e.g.
$SecretFolders = #{} #at top of your script, outside loops
# in loops:
if (-not $SecretFolders.ContainsKey($line.CompanyName))
{
$SecretFolders[$line.CompanyName] = -join (random name generation here)
}
$SecretFolder = $SecretFolders[$line.CompanyName]
I'm trying to get The Folder Info and Security Info for all the folders on our server.
But I'm not to familiar with Powershell here. Mind helping a newbie?
How to do I get the Security acl piped into the Text file?
Along with just the member objects of Folder Name, Size, sub folder count?
# Step 1 Get Folder Path
function Select-Folder($message='Select a folder', $path = 0) {
$object = New-Object -comObject Shell.Application
$folder = $object.BrowseForFolder(0, $message, 0, $path)
if ($folder -ne $null) {
$folder.self.Path
}
}
#Step 2:Search For Directories
$dirToAudit = Get-ChildItem -Path (Select-Folder 'Select some folder!') -recurse | Where {$_.psIsContainer -eq $true}
foreach ($dir in $dirToAudit)
{
#Step 3: Output: [Folder Path, Name, Security Owner, Size, Folder Count]
#Pipe To CSV Text File
Get-Acl -Path $dir.FullName | Select-Object PSPath, Path,Owner | export-csv C:\temp\SecurityData.csv
#I also want the Folder path, Size and SubFolder Count
}
#Step 4: Open in Excel
invoke-item -path C:\temp\SecurityData.csv
Here's some sites that I found useful on the subject: http://blogs.msdn.com/b/powershell/archive/2007/03/07/why-can-t-i-pipe-format-table-to-export-csv-and-get-something-useful.aspx
http://www.maxtblog.com/2010/09/to-use-psobject-add-member-or-not/
This task isn't particularly easy. First you will want to create a custom object that contains the properties you want. These properties will be added via different commands e.g.:
$objs = Get-ChildItem . -r |
Where {$_.PSIsContainer} |
Foreach {new-object psobject -prop #{Path=$_.FullName;Name=$_.Name;FolderCount=$_.GetDirectories().Length}}
$objs = $objs | Foreach { Add-Member NoteProperty Owner ((Get-Acl $_.Path).Owner) -Inp $_ -PassThru}
$objs | Export-Csv C:\temp\data.csv
Getting the folder size will take some extra work to compute.