Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Toast Museum
Dec 3, 2005

30% Iron Chef
Yep, a Hashtable or Dictionary is what you want for taking a department and selecting its file.

Depending on how the script is going to be used, consider making it a function. That way, you could include an enum of department names, and the function's -Dept parameter could be limited to accept only values from the enum. As a bonus, you'd get tab-completion on the parameter. I can get into more detail if it's something you think you might want to do.

Adbot
ADBOT LOVES YOU

incoherent
Apr 24, 2004

01010100011010000111001
00110100101101100011011
000110010101110010
anything to make it "proper" or the right way.

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin

I like to pronounce it "hash-tuh-bull" sorta rhyming with mashable.

incoherent
Apr 24, 2004

01010100011010000111001
00110100101101100011011
000110010101110010
Thanks again everyone. I got a fully functional script to do what I needed to do and sorry for bumbling into, and making GBS threads on the carpet, of this fine thread. Even added some parameters requirements and auto tab complete the parameters that were needed so it is 100% self contained.

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


incoherent posted:

Thanks again everyone. I got a fully functional script to do what I needed to do and sorry for bumbling into, and making GBS threads on the carpet, of this fine thread. Even added some parameters requirements and auto tab complete the parameters that were needed so it is 100% self contained.

Listen pal, I've shat the carpet in WAY nicer places than here. You're fine, we've all filled that quota. :shobon:

Potato Salad
Oct 23, 2014

nobody cares


it's kind of cool that people will organically walk into the need for the kinds of structures that people learn in CS classes, where a kid who learns what a hashtable is in CS might never actually use such a structure in their life

ModeSix
Mar 14, 2009

I have a use case where I need to execute a process, wait for it to either complete successfully or if it is still running terminate it and try again. If it terminated successfully I need to start another process/function/whatever they are called in powershell to send an email with the contents of the first command output.

I literally know nothing about Powershell except what I've been able to Google.

code:
for ($i=0; $i -le $max_iterations; $i++)
{
    $proc = Start-Process -filePath $programtorun -ArgumentList $argumentlist -workingdirectory $programtorunpath -PassThru

    # keep track of timeout event
    $timeouted = $null # reset any previously set timeout

    # wait up to x seconds for normal termination
    $proc | Wait-Process -Timeout 4 -ErrorAction SilentlyContinue -ErrorVariable timeouted

    if ($timeouted)
    {
        # terminate the process
        $proc | kill

        # update internal error counter
    }
    elseif ($proc.ExitCode -ne 0)
    {
        # update internal error counter
    }
}
This is what I have found on Stackoverflow which appears to do at least half of what I am looking for.

How can I make the loop restart after it's killed in the if ($timedout) portion of the loop?

Basically there's an Access database that has a built in function to generate a couple csv files, it gets hung up sometimes and doesn't complete and has to be manually killed. I'd like to have the ability to have this run it, watch it for 90 seconds, if it's still not done after 90 seconds kill it and start over.

I hope that random mishmash of ideas makes sense.

Mario
Oct 29, 2006
It's-a-me!
continue should do it https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_continue?view=powershell-7.2

Submarine Sandpaper
May 27, 2007


return will leave the loop if you have a successful first run

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
Powershell implementation horror of the day:

What does this snippet of code output, and why?

code:
set-content C:\temp\foo.txt -Value "hello world"
$content = get-content C:\temp\foo.txt 
@{ name = $content } | convertto-json -compress
Once I saw the output, I immediately realized what I did wrong, but it's awful, unintuitive behavior.

Potato Salad
Oct 23, 2014

nobody cares


:itwaspoo:

Toast Museum
Dec 3, 2005

30% Iron Chef

New Yorp New Yorp posted:

Powershell implementation horror of the day:

What does this snippet of code output, and why?

code:
set-content C:\temp\foo.txt -Value "hello world"
$content = get-content C:\temp\foo.txt 
@{ name = $content } | convertto-json -compress
Once I saw the output, I immediately realized what I did wrong, but it's awful, unintuitive behavior.

Yikes, that is rough. The good news is, it's fixed as of PowerShell 7.2 for string and DateTime. If you're stuck with PowerShell 5.1, one workaround is
PowerShell code:
@{ name = $content.PSObject.BaseObject } | ConvertTo-Json -Compress

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Toast Museum posted:

Yikes, that is rough. The good news is, it's fixed as of PowerShell 7.2 for string and DateTime. If you're stuck with PowerShell 5.1, one workaround is
PowerShell code:
@{ name = $content.PSObject.BaseObject } | ConvertTo-Json -Compress

Yeah, I realized the problem and the workaround. It's just an annoying footgun that bites me every year or two and leads to confusion until I remember why it's happening and what the fix is.

klosterdev
Oct 10, 2006

Na na na na na na na na Batman!
Newbie Powershell question, I'm trying to figure out how to powershell forcing a password reset on next login to specific users in Azure AD, but it looks like the only way to do so it by specifying object ID, and I'd like to do it by selecting userprincipalname. How do I combine

Get-AzureADUser -ObjectId "name@domain.com" | select objectid

with

Set-AzureADUserPassword -ObjectId "ObjectIDGoeshere" -ForceChangePasswordNextLogin 1

FISHMANPET
Mar 3, 2007

Sweet 'N Sour
Can't
Melt
Steel Beams

klosterdev posted:

Newbie Powershell question, I'm trying to figure out how to powershell forcing a password reset on next login to specific users in Azure AD, but it looks like the only way to do so it by specifying object ID, and I'd like to do it by selecting userprincipalname. How do I combine

Get-AzureADUser -ObjectId "name@domain.com" | select objectid

with

Set-AzureADUserPassword -ObjectId "ObjectIDGoeshere" -ForceChangePasswordNextLogin 1

PowerShell code:
$user = Get-AzureADUser -ObjectId "name@domain.com"
Set-AzureADUserPassword -ObjectId $user.objectid -ForceChangePasswordNextLogin 1
Store the user object in the variable $user, then use the objectid property of that object when you call the Set-AzureADUserPassword command.

klosterdev
Oct 10, 2006

Na na na na na na na na Batman!
Thanks!

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

klosterdev posted:

Newbie Powershell question, I'm trying to figure out how to powershell forcing a password reset on next login to specific users in Azure AD, but it looks like the only way to do so it by specifying object ID, and I'd like to do it by selecting userprincipalname. How do I combine

Get-AzureADUser -ObjectId "name@domain.com" | select objectid

with

Set-AzureADUserPassword -ObjectId "ObjectIDGoeshere" -ForceChangePasswordNextLogin 1

Without knowing the behavior of those particular cmdlets, you may be able to just pipe the one to the other. Powershell is frequently good about inferring the way objects fit together. And sometimes infuriating bad.


code:

Get-AzureADUser -ObjectId "name@domain.com"  | Set-AzureADUserPassword -ForceChangePasswordNextLogin 1

Toast Museum
Dec 3, 2005

30% Iron Chef
Checking the docs, Get-AzureADUser's return object includes an ObjectID property, and Set-AzureADUserPassword's -ObjectID parameter accepts pipeline input, so piping one to the other should work fine.

That said, some of Microsoft's examples indicate that Set-AzureADUserPassword -ObjectID should accept a UPN directly, so there should be no need to pipe from Get-AzureADUser at all.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!
So, I'm trying to introduce the team at work to concepts like "functions" and "not writing things whole cloth every week that are impossible to QC because you aren't reusing code and nobody knows what you are trying to do". And it's an adventure because idk what I'm really doing and so I'm just looking for pointers on how to Best Practice this stuff. The team is fairly receptive to changes I've previously proposed, and they've stated interest in standardizing things going forward, but they've got even less idea what that would look like than I do, and are largely content to just winging it for another decade, unless someone sets the direction for them.

So, like, here's an example of one I wrote up this morning. Common piece of code we do is stopping services before an install, but standardizing it into a robust piece with logging so they can just yeet stuff at it and it will Just Work but also make logs, would cut down on time spent and also make it easier to QC.

Idk if anyone has any thoughts about whether I'm approaching it the right way, or if there's a better way to handle it. Really open to any suggestions.


PowerShell code:
function CSSDT-Stop-Service {
<#
	.SYNOPSIS
			A function that stops a service passed via pipeline
	.PARAMETERS
			 $service - Pipeline passed list of services
			 $Timeout - Timeout to wait for job completion.  Default=30s
	.RETURNS
			ExitCode: [String] True if service not present or if service present and successfully stopped.  Otherwise false.
			ExitMessage: [String] Interpreted error message.
	.USAGE
			 $ServiceResult = Get-Service "Winzip*" | CSSDT-Stop-Service
			 if(-not $ServiceResult.ExitCode) { LogLine "Error: [$($ServiceResult.ExitMessage)]" }
#>

	[CmdletBinding()]

	Param(
		[Parameter(Mandatory=$true,
		ValueFromPipeline=$true)]
			$service,
		[Parameter()]
			[int]$Timeout=30
	)

	process {
		$jobs = $Null
		$ExitCode = $True
		$ExitMessage = ""

		ForEach($current_service in $service) {
			echo "Stopping Service $($current_service.name)"
			$jobs += Start-Job -ScriptBlock {Stop-Service $input.Name } -inputObject $current_service
		}

		echo "Waiting up to $($Timeout) seconds for jobs to process..."
		$jobs | Wait-Job -Timeout -$Timeout | Out-Null

		ForEach($current_job in $(Get-Job $jobs)) {

			switch ($current_job.State) {
				"NotStarted" { $Exitcode=$False; $ExitMessage+="Error: Job not Started ($($current_job.Name)"}
				"Running" { $Exitcode=$False; $ExitMessage+="Error: Job Timed Out ($($current_job.Name)"}
				"Failed" { $Exitcode=$False; $ExitMessage+="Error: Failed ($($current_job.Name)"}
				"Blocked" { $Exitcode=$False; $ExitMessage+="Error: Job Blocked ($($current_job.Name)"}
			}

			if($current_job.Error) {
				$ExitCode = $False
				$ExitMessage = "Error: Stop-Service command returned error: $($current_job.error)"
			}
		}

		ForEach($current_service in $service) {
			if((Get-Service $current_service).Status -eq "Running") {
				$ExitCode = $False
				$ExitMessage = "Error: Post-check Failed.  Service $($current_service.Name) still running..."
			}
		}

		if($ExitCode) {
			echo "Service stopped..."
		} else {
			echo "Error: Service stop failure.  Exit Message [$($ExitMessage)]"
		}

		return @{ExitCode=$ExitCode; ExitMessage=$ExitMessage}
	}
}
PS: The echo calls are actually calls to an internal logging function that I've replaced for readability.

Toshimo fucked around with this message at 00:28 on Jun 9, 2022

nielsm
Jun 1, 2009



First, check what's going on with your copy-paste. All the line breaks are double on the forums, and the indentation looks uneven, especially in the documentation block. (Also, 16 spaces indentation is weird too.)

As far as I can tell from reading the code, if you send in services by the pipeline, they're going to be processed sequentially with waiting for the timeout for each individual service. It would run the timeouts in parallel only if you passed the services as an array in a single parameter.
If your intention is to process the timeout for all the service stopping in parallel then you'd have to only start those jobs in the Process{} block, and then do all the remaining work in the End{} block, which runs after the pipeline input to the cmdlet has finished.

The basics of CmdletBinding and functions with Process{} that take input from the pipeline, is that the Process{} block is an implicit loop over each object on the pipeline, so treat it as that.
The exception to that is if the type of the pipeline parameter allows array types and you pass the input object as an array as a parameter instead of through pipeline, then the Process{} block runs once with the array as input, and in that case you'd have to do an internal foreach loop over that.
So what I want to say is, if you want to allow passing an array of services as a parameter and have it work, then keep the foreach loop inside the Process{} block too.

Your return values are odd.
The best way to return objects to the pipeline is actually to not use the return statement but just leave them to output.
Additionally, you should normally not return a hashtable, but use the [PSCustomObject] pattern to convert hashtables to objects that behave nicer and work with the standard formatting and output cmdlets.

Consider the standard PowerShell function naming scheme, "Verb-Noun". Stuffing extra terms in front of the verb is bad practice.

PowerShell code:
function Stop-CSSDTService {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
    $Service,
    [Parameter()]
    [int] $Timeout = 30
  )

  Begin {
    $jobs = @()
  }

  Process {
    foreach ($s in $Service) {
      Write-Host "Stopping service $($s.Name)"
      $jobs =+ Start-Job -ScriptBlock {Stop-Service $input.Name } -inputObject $current_service
    }
  }

  End {
    Write-Host "Waiting up to $Timeout seconds for jobs to process..."
    $jobs | Wait-Job -Timeout -$Timeout | Out-Null

    $exitCode = $true
    $exitErrors = @()
    foreach ($j in (Get-Job $jobs)) {
      switch ($j.State) {
        "NotStarted" { $exitCode = $False; $exitErrors += "Error: Job not Started ($($current_job.Name)" }
        "Running" { $exitCode = $False; $exitErrors += "Error: Job Timed Out ($($current_job.Name)" }
        "Failed" { $exitCode = $False; $exitErrors += "Error: Failed ($($current_job.Name)" }
        "Blocked" { $exitCode = $False; $exitErrors += "Error: Job Blocked ($($current_job.Name)" }
      }

      if ($j.Error) {
        $exitCode = $false
        $exitErrors += "Error: Stop-Service command returned error: $($current_job.error)"
      }
    }

    # etc... missing code

    [PSCustomObject]@{
      ExitCode = $exitCode;
      Errors = $exitErrors;
    }
  }
}
The entire way of returning the status seems a little odd to me, but I'm not sure if you intend to connect it with other things on pipeline that want to consume the output.
It's often a good idea to try to structure data all the way through, including returns, rather than formatting for text display only.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

nielsm posted:

First, check what's going on with your copy-paste. All the line breaks are double on the forums, and the indentation looks uneven, especially in the documentation block. (Also, 16 spaces indentation is weird too.)

Yeah, something went bad copy/pasting it from my email on mobile (also I need to remind the Awful.apk devs that Powershell is a supported language now).

nielsm posted:

As far as I can tell from reading the code, if you send in services by the pipeline, they're going to be processed sequentially with waiting for the timeout for each individual service. It would run the timeouts in parallel only if you passed the services as an array in a single parameter.
If your intention is to process the timeout for all the service stopping in parallel then you'd have to only start those jobs in the Process{} block, and then do all the remaining work in the End{} block, which runs after the pipeline input to the cmdlet has finished.

The basics of CmdletBinding and functions with Process{} that take input from the pipeline, is that the Process{} block is an implicit loop over each object on the pipeline, so treat it as that.
The exception to that is if the type of the pipeline parameter allows array types and you pass the input object as an array as a parameter instead of through pipeline, then the Process{} block runs once with the array as input, and in that case you'd have to do an internal foreach loop over that.
So what I want to say is, if you want to allow passing an array of services as a parameter and have it work, then keep the foreach loop inside the Process{} block too.

Yeah, I wasn't familiar with any of this, so thanks, I'll definitely invest the time into updating my stuff this way, as it'll be a lot more useful. I'm basically working from scratch and I just don't know the things I don't know.

nielsm posted:

Your return values are odd.
The best way to return objects to the pipeline is actually to not use the return statement but just leave them to output.
Additionally, you should normally not return a hashtable, but use the [PSCustomObject] pattern to convert hashtables to objects that behave nicer and work with the standard formatting and output cmdlets.

This, too. It's very much a "I got things to work by doing this, so this is the way I know to do it".

nielsm posted:

Consider the standard PowerShell function naming scheme, "Verb-Noun". Stuffing extra terms in front of the verb is bad practice.

Yes, I do know this is non-standard, but because I'm working with a group who doesn't have a deep familiarity, I'm prepending everything that is internal with the name of our team so that they can readily identify the inhouse pieces from the standard stuff.


nielsm posted:

[code=powershell]

Thanks for this, I'll see about getting things update in the morning.

nielsm posted:

The entire way of returning the status seems a little odd to me, but I'm not sure if you intend to connect it with other things on pipeline that want to consume the output.
It's often a good idea to try to structure data all the way through, including returns, rather than formatting for text display only.

I don't really have a process in place, so no, I wasn't planning on doing other stuff with this. My primary goal is to just start reducing the overhead of a lot of our common stuff to shave off errors and QC time, and then I can revisit it later for better functionality once we've got some breathing room and some more people who know what's up.

guppy
Sep 21, 2004

sting like a byob
I am an extremely casual user of PowerShell, but one thing I find helpful when writing larger stuff with a bunch of different functions is, before I write so much as a single line of code, breaking everything down in writing -- can be on paper, can be on the computer -- into the component functions that I'm going to need to write. Sometimes those functions will imply the need for additional functions, so I write those down too. This way, before I write, I have a list of what functions I'm going to need.

The reason I find this helpful, other than the fact that it obviously makes it easier to organize and wrap my head around a larger project, is that it helps me to compartmentalize that functionality. I am going to need to do thing x a lot, I don't have to worry about it when I'm writing this other function because the logic exists in this other function that I already wrote (or am going to write). So I can just reference that function by name and assume it will return what I need, when I need it. When I write that second function, it's easier to think about it in just its own context than in the large scope of the program.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!
Yeah, my shop is weird (or maybe not) because:
  • 95% of what we write is installation wrappers.
  • Half the team is old dudes who did WiseScript for like a decade and 1 of them is now mostly MSIs and does Powershell only when neccessary.
  • We have exactly 1 piece of shared code, which is a single include file that just sets up logging and populates a bunch of environment variables.
  • We write a bunch of small stuff on short notice that often gets yeeted out to prod for 5+ years and is never touched again. (We don't patch code)
  • Everything has to work the first time, every time, because if a script fails 1% of the time, that's a loss larger than what any of us make in a year.
  • We don't have any source control.
  • We QC each others' stuff, but I'm not convinced any of us really knows wtf is going on with each others' code more than 50% of the time, because we have to jam in a bunch of edge case poo poo and documentation is often non-existent.

It's weird, and not conducive to learning or improvement, but at least it's a bunch of good eggs who are willing to accept new things and improve, so if I can fix me, I can port that stuff over to everyone.

Zaepho
Oct 31, 2013

Toshimo posted:

Yeah, my shop is weird (or maybe not) because:
  • 95% of what we write is installation wrappers.

Have you looked at https://psappdeploytoolkit.com/? It has a bunch of pre-canned stuff specifically for app deployments that you might be able to make use of and let somebody else maintain and improve.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

Zaepho posted:

Have you looked at https://psappdeploytoolkit.com/? It has a bunch of pre-canned stuff specifically for app deployments that you might be able to make use of and let somebody else maintain and improve.

It is certainly something I've considered, when we get enough breathing room that I can start looking at better solutions, but for the moment, I've got an overwhelming backlog of several thousand applications that I have to review, so I fix what I can, and push the big stuff to next year's Toshimo.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Toshimo posted:

[*] We don't have any source control.
[/list]

This is insane and needs to be fixed immediately. There is zero excuse to not use source control and any manager who hasn't enforced it years ago is straight up incompetent.

Also, start using Pester to write tests for your scripts.

Then take your newfound source control and hook it up to a CI system and run the tests on every commit.

New Yorp New Yorp fucked around with this message at 06:30 on Jun 9, 2022

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

New Yorp New Yorp posted:

This is insane and needs to be fixed immediately. There is zero excuse to not use source control and any manager who hasn't enforced it years ago is straight up incompetent.

Also, start using Pester to write tests for your scripts.

Then take your newfound source control and hook it up to a CI system and run the tests on every commit.

Yeah, we just have everything tossed up on a SMB share. My boss is all for source control, as is my team, and I've got a BitBucket set aside for it, but I haven't had enough time to figure out how I'm going to use it (again, we've got several thousand scripts that never really get updated, so it's a weird case).

I'll look into Pester, thanks.

EoRaptor
Sep 13, 2003

by Fluffdaddy
Good luck feeding Stop-Service a service that doesn't exist. Also, good luck checking if a service exists before feeding it to Stop-Service.

Toshimo posted:

It is certainly something I've considered, when we get enough breathing room that I can start looking at better solutions, but for the moment, I've got an overwhelming backlog of several thousand applications that I have to review, so I fix what I can, and push the big stuff to next year's Toshimo.

Master Packager sits on top of psappdeploytoolkit, and wraps a bunch of its options into checkboxes that you can then make templates for. Literally drag and drop msi's into a window. It'll do fancier stuff if you pay. (no affiliation)

EoRaptor fucked around with this message at 04:04 on Jun 11, 2022

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

EoRaptor posted:

Also, good luck checking if a service exists before feeding it to Stop-Service.


Get-service |? { $_.name -eq 'whatever'}

EoRaptor
Sep 13, 2003

by Fluffdaddy

New Yorp New Yorp posted:

Get-service |? { $_.name -eq 'whatever'}

Yeah, now that I reread what I wrote, I realized I’d memory holed the other part of the issue I faced, which was a security product that hid its service and process. I just remembered the frustration.

But do check for a service existing before using Stop-Service, its error handling is terrible.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!
I am losing my goddamn mind and this has to be the simplest thing.


PowerShell code:

clear

$input_file="C:\Users\266520\Documents\test-data.txt"

&#160;

$payload = Get-Content $input_file

&#160;

echo "---"

echo "File Contents:"

echo $payload

echo "---"

&#160;

$payload -match '(?<dollars>\d+)\.(?<cents>\d+)'

$Matches

Output:



---

File Contents:

Alpha,1,2/3/22,22.99,76.70,123-45-6789

Beta,999,4/5/1999,.75,63.69,234-56-789

---

Alpha,1,2/3/22,22.99,76.70,123-45-6789

Beta,999,4/5/1999,.75,63.69,234-56-789

 

Name                           Value                                                                                                                                                  

----                           -----                                                                                                                                                  

domain                         CONTOSO                                                                                                                                               

user                           jsmith                                                                                                                                                 

0                              was CONTOSO\jsmith        
    


Why the heck is $Matches not populating and why am I not getting a boolean output from -match?

Toshimo fucked around with this message at 19:10 on Aug 10, 2022

The Fool
Oct 16, 2003


Of the top of my head I see two issues:

-match works on strings, $payload is an array of strings

$Matches isn't getting set anywhere, so I'm not sure what you expect its value to be.

The Fool
Oct 16, 2003


To solve the first issue, I would do something like this:
code:
ForEach ($line in $payload) {$line -match '(?<dollars>\d+)\.(?<cents>\d+)'}

Toshimo
Aug 23, 2012

He's outta line...

But he's right!
Thanks, yeah, I forgot that Get-Member doesn't tell you that it's an array unless you use -inputObject because reasons... Which I still don't think -match should just drop on the floor, but here we are.

Toast Museum
Dec 3, 2005

30% Iron Chef
To come at the problem from another direction, if the sample data is representative of how the real data looks, have you considered using Import-Csv instead of messing around with regex?

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

Toast Museum posted:

To come at the problem from another direction, if the sample data is representative of how the real data looks, have you considered using Import-Csv instead of messing around with regex?

I did, but it's not my data, and the only thing the person wants is to be able to change the money amounts easily, instead of having to do it in excel one-by-one. I had expected it to be a quick thing I knocked out over coffee until I got side-tracked over -match being buggy.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Toshimo posted:

I did, but it's not my data, and the only thing the person wants is to be able to change the money amounts easily, instead of having to do it in excel one-by-one. I had expected it to be a quick thing I knocked out over coffee until I got side-tracked over -match being buggy.

Use import-csv and export-csv. They are designed for reading and writing csv data.

Mario
Oct 29, 2006
It's-a-me!
And remember to use -NoTypeInformation on this if you are not on v6+

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

New Yorp New Yorp posted:

Use import-csv and export-csv. They are designed for reading and writing csv data.

I understand what they are for, but I have never seen the data, so I don't even know if they are in legit CSV format or anything.

Adbot
ADBOT LOVES YOU

NPR Journalizard
Feb 14, 2008

Im trying to use the PowerBI cmdlet to do a survey of the datasets in my tenant. I can get a list of datasets fairly easily with Get-PowerBIDataset, but I also want to get a list of what tables each dataset uses. Supposedly Get-PowerBITable does this, but no matter what parameters I pass, or what login I use, including a service admin account, I cant get anything out of it other than an error message saying not found.

Have tried searching the web for this but cant really find an answer from a reliable source, other than one post on the community forums that I hope is wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply